
#include "stdafx.h"
/* standard libraries to use: */
#include <string.h>
#include <math.h>
//#include "hxtypes.h"

/* some math. constants: */
#ifndef M_PI
#define M_PI      3.14159265358979323846
#endif
#ifndef M_SQRT2
#define M_SQRT2   1.41421356237309504880
#endif

/* fast rounding to a nearest integer: */
#if _M_IX86
static __inline int INT(double a)
{
	int ia;
	__asm   fld     a
		__asm   fistp   ia
		return ia;
}
#elif defined(__i386) && defined(_LINUX)
static inline int INT(double a)
{
	int ia;
	__asm__ (
		" fldl %1; "
		" fistpl %0; "
		: "=m"(ia)
		: "m"(a)
		: "memory", "st"
		);

	return ia;
}

#else
#define INT(a) ((int) (((a)<0)? ((a)-0.5): ((a)+0.5)))
#endif

/* macros to check big/little endiannes of the system: */
// #ifdef _MACINTOSH
// const static union {char c[4]; UINT32 l;} _1234 = {''001'002'003'004'}; /* Flawfinder: ignore */
// #else
// const static union {char c[4]; UINT32 l;} _1234 = {"'001'002'003'004"}; /* Flawfinder: ignore */
// #endif
#define BIG_ENDIAN      0/*(_1234.l == 0x01020304)*/
#define LITTLE_ENDIAN   1/*(_1234.l == 0x04030201)*/

/* get our interface: */
#include "ColorConvert.h"

/*
* CCIR Rec. 601-2 definition of YCrCb color space.
*
* Given a primary analogue RGB signal (R,G,and B components are in the
* range of 0..1 volt), the luminance signal is defined as:
*      Y = 0.299 R + 0.587 G + 0.114 B.
* Signals of color-defferences, are therefore:
*      (R-Y) = 0.701 R - 0.587 G - 0.114 B, and
*      (B-Y) = -0.299 R - 0.587 G + 0.886 B.
* Using normalization (we want (R-Y) and (B-Y) to be in the range of
* -0.5..0.5 volt), we will obtain:
*      Cr = 0.5/0.701 (R-Y), and
*      Cb = 0.5/0.886 (B-Y).
* Finally, the quantized versions of Y,Cr,and Cb are defined as:
*      Y'  = 219 Y + 16,
*      Cr' = 224 Cr + 128, and
*      Cb' = 224 Cb + 128.
*
* For convenience, we will use the following names for these constants
* (here and below: V = Cr, and U = Cb):
*/
#define CCIR601_YRCOEF  0.299
#define CCIR601_YGCOEF  0.587
#define CCIR601_YBCOEF  0.114

#define CCIR601_YMAX    219
#define CCIR601_YMED    ((double)CCIR601_YMAX/2.)
#define CCIR601_YOFFSET 16

#define CCIR601_VMAX    224
#define CCIR601_VOFFSET 128

#define CCIR601_UMAX    224
#define CCIR601_UOFFSET 128

/*
* Also, we typically will deal with quantized R'G'B' signal, represented
* by 8-bit quantities for R', G' and B' components:
*/
#define RGB_MAX 255

/*
* Forward R'G'B'->Y'Cr'Cb' conversion:
*  a) calculate Y":
*      Y" = 0.299 R' + 0.587 G' + 0.114 B';		=> 3 muls/lookups
*  b) calculate Y',Cr',Cb' values:
*      Y'  = 219/255 Y" + 16;				   		=> 1 mul/lookup
*      Cr' = 224/255 * 0.5/0.701 (R'-Y") + 128;	=> 1 mul/lookup
*      Cb' = 224/255 * 0.5/0.886 (B'-Y") + 128;	=> 1 mul/lookup
*/
#define YSCALE  ((double)CCIR601_YMAX/RGB_MAX)
#define VSCALE  ((double)CCIR601_VMAX/RGB_MAX * 0.5/(1.-CCIR601_YRCOEF))
#define USCALE  ((double)CCIR601_UMAX/RGB_MAX * 0.5/(1.-CCIR601_YBCOEF))

#define YMAX    (RGB_MAX + 3)       /* include max. rounding error */
#define VMAX    (int)((double)(1.-CCIR601_YRCOEF) * RGB_MAX + 1)
#define VMIN    VMAX
#define UMAX    (int)((double)(1.-CCIR601_YBCOEF) * RGB_MAX + 1)
#define UMIN    UMAX

/* R'G'B' -> Y'Cr'Cb' conversion tables: */
static int yrtab [RGB_MAX+1], ygtab [RGB_MAX+1], ybtab [RGB_MAX+1];
static int yytab [YMAX+1], vrytab [VMIN+VMAX+1], ubytab [UMIN+UMAX+1];

/*
* Backward Y'Cr'Cb'->R'G'B' conversion:
*  a) calculate Y":
*      Y"  = 1/(219/255) (Y'-16);				   		=> 1 mul/lookup
*  b) calculate R'B':
*      R'  = Y" + 1/(224/255 * 0.5/0.701) (Cr'-128);	=> 1 mul/lookup
*      B'  = Y" + 1/(224/255 * 0.5/0.886) (Cb'-128); 	=> 1 mul/lookup
*  c) calculate G':
*      G'  = 1/0.587 (Y" - 0.299 R' - 0.114 B') =
*          = Y" - 0.299/0.587/(224/255 * 0.5/0.701) (Cr'-128)
*               - 0.114/0.587/(224/255 * 0.5/0.886) (Cb'-128); => 2 muls/luts
*/
#define YCOEF   (1/YSCALE)
#define RVCOEF  (1/VSCALE)
#define GVCOEF  (-CCIR601_YRCOEF/CCIR601_YGCOEF/VSCALE)
#define GUCOEF  (-CCIR601_YBCOEF/CCIR601_YGCOEF/USCALE)
#define BUCOEF  (1/USCALE)

/* Y'Cr'Cb'->R'G'B' conversion tables: */
static int ytab  [RGB_MAX+1], rvtab [RGB_MAX+1], gvtab [RGB_MAX+1];
static int gutab [RGB_MAX+1], butab [RGB_MAX+1];
static int rutab [RGB_MAX+1], bvtab [RGB_MAX+1]; /* alpha != 0 */

/*
* Color adjustments.
*  a) hue: in NTSC YUV color space, the hue adjustment is equivalent
*    to the UV axes rotation:
*      V' = V cos(alpha) - U sin(alpha);
*      U' = V sin(alpha) + U cos(alpha);
*    where:
*      V = (R-Y)/1.14;
*      U = (B-Y)/2.03;
*    In YCrCb color space, this will be equivalent to:
*      Cr' - 128 = (Cr - 128) cos(alpha) - zeta (Cb - 128) sin(alpha));.
*      Cb' - 128 = xi (Cr - 128) sin(alpha) + (Cb - 128) cos(alpha);
*    where:
*      xi   = (1./(0.5/0.701)/1.14)/(1./(0.5/0.886)/2.03);
*      zeta = 1/xi;
*  b) saturation:
*      Cr' - 128 = beta (Cr - 128);
*      Cb' - 128 = beta (Cb - 128);
*  c) brightness:
*      Y' - 16 = gamma (Y - 16);
*      Cr' - 128 = gamma (Cr - 128);
*      Cb' - 128 = gamma (Cb - 128);
*  d) contrast:
*      Y' - 16 = lambda + kappa (Y - 16);
*  e) all together:
*      Y' - 16   = gamma (lambda + kappa (Y - 16));
*      Cr' - 128 = gamma beta ((Cr - 128) cos(alpha) - zeta (Cb - 128) sin(alpha));
*      Cb' - 128 = gamma beta (xi (Cr - 128) sin(alpha) + (Cb - 128) cos(alpha));
*/
#define XI      (((1.-CCIR601_YRCOEF)/0.5/1.14)/((1.-CCIR601_YBCOEF)/0.5/2.03))
#define ZETA    (1./XI)

/* empirically choosen limits for color adjustments: */
#define ALPHA_MAX   (M_PI*3/4)
#define ALPHA_MED   0.              /* hue */
#define ALPHA_MIN   (-M_PI*3/4)

#define BETA_MAX    M_SQRT2
#define BETA_MED    1.              /* saturation */
#define BETA_MIN    (M_SQRT2/4)

#define GAMMA_MAX   M_SQRT2
#define GAMMA_MED   1.              /* brightness */
#define GAMMA_MIN   0.5

#define KAPPA_MIN   0.5
#define KAPPA_MED   1.              /* contrast */
#define KAPPA_MAX   2.

#define LAMBDA(kappa)   (CCIR601_YMED * (1. - kappa))

/* current color adjustment parameters: */
static float cur_brightness, cur_contrast, cur_saturation, cur_hue;
static int is_alpha, is_beta, is_gamma, is_kappa;
static int color_conversion_tables_inited = 0;

/* Y'Cr'Cb'->Y'Cr'Cb' conversion tables: */
static int _yytab [RGB_MAX+1], _uutab [RGB_MAX+1], _vvtab [RGB_MAX+1];
static int _uvtab [RGB_MAX+1], _vutab [RGB_MAX+1]; /* alpha != 0: */

/*
* Clipping & dithering:
*
* Note: the CLIPNEG/CLIPPOS numbers are somewhat rounded values
*  that correspond to current GAMMA_MAX,KAPPA_MAX, and BETA_MAX
*  parameters. If you are planning to modify any of these, the
*  ranges of the clip tables shall be adjusted as well.
*/
#define CLIPRNG 256                 /* unclipped range */
#define CLIPNEG (288 * 4)           /* rounded max neg. value */
#define CLIPPOS (288 * 4)           /* rounded max shot over 256 */

#define CLIP4 (clip4+CLIPNEG)       /* offset into clip4 */
#define CLIP5 (clip5+CLIPNEG)       /* offset into clip5 */
#define CLIP6 (clip6+CLIPNEG)       /* offset into clip6 */
#define CLIP8 (clip8+CLIPNEG)       /* offset into clip8 */

/* actual clip tables */
static unsigned char clip4 [CLIPNEG+CLIPRNG+CLIPPOS]; /* clip/round to 4 bits */ /* Flawfinder: ignore */
static unsigned char clip5 [CLIPNEG+CLIPRNG+CLIPPOS]; /* clip/round to 5 bits */ /* Flawfinder: ignore */
static unsigned char clip6 [CLIPNEG+CLIPRNG+CLIPPOS]; /* clip/round to 6 bits */ /* Flawfinder: ignore */
static unsigned char clip8 [CLIPNEG+CLIPRNG+CLIPPOS]; /* clip to 8 bits */ /* Flawfinder: ignore */

/* 2-level, 2x2 dither noise, added before rounding to 333/555/565.
* Define NO_DITHER to disable. */
#ifndef NO_DITHER
#define DITH3L  8   /* 16 - 8 */
#define DITH3H  24  /* 16 + 8 */
#define DITH4L  4   /* 8 - 4 */
#define DITH4H  12  /* 8 + 4 */
#define DITH5L  2   /* 4 - 2 */
#define DITH5H  6   /* 4 + 2 */
#define DITH6L  1   /* 2 - 1 */
#define DITH6H  3   /* 2 + 1 */
#else /* disabled */
#define DITH3L  16  /* does (i+16)>>5 for proper rounding */
#define DITH3H  16
#define DITH4L  8   /* does (i+8)>>4 for proper rounding */
#define DITH4H  8
#define DITH5L  4   /* does (i+4)>>3 for proper rounding */
#define DITH5H  4
#define DITH6L  2   /* does (i+2)>>2 for proper rounding */
#define DITH6H  2
#endif

/* speeds-up calculation of distance between pixels: */
#define SQ  (sq+RGB_MAX+1)
static unsigned int sq [RGB_MAX+1+RGB_MAX];

/* palette color maps: */
unsigned char pmap [1U << (4+4+4)];  /* 4-bits per channel */ /* Flawfinder: ignore */

/* default palette to use: */
static unsigned int default_palette [RGB_MAX+1] = {
	0x000000, 0x000080, 0x008000, 0x008080, 0x800000, 0x800080, 0x808000, 0xC0C0C0,
	0xC0DCC0, 0xF0CAA6, 0x040404, 0x080808, 0x0C0C0C, 0x111111, 0x161616, 0x1C1C1C,
	0x222222, 0x292929, 0x555555, 0x4D4D4D, 0x424242, 0x393939, 0x818181, 0x000081,
	0x008100, 0x008181, 0x810000, 0x810081, 0x818100, 0x000033, 0x000066, 0x000099,
	0x0000CC, 0x003300, 0x003333, 0x003366, 0x003399, 0x0033CC, 0x0033FF, 0x006600,
	0x006633, 0x006666, 0x006699, 0x0066CC, 0x0066FF, 0x009900, 0x009933, 0x009966,
	0x009999, 0x0099CC, 0x0099FF, 0x00CC00, 0x00CC33, 0x00CC66, 0x00CC99, 0x00CCCC,
	0x00CCFF, 0x00FF66, 0x00FF99, 0x00FFCC, 0x330000, 0x330033, 0x330066, 0x330099,
	0x3300CC, 0x3300FF, 0x333300, 0x333333, 0x333366, 0x333399, 0x3333CC, 0x3333FF,
	0x336600, 0x336633, 0x336666, 0x336699, 0x3366CC, 0x3366FF, 0x339900, 0x339933,
	0x339966, 0x339999, 0x3399CC, 0x3399FF, 0x33CC00, 0x33CC33, 0x33CC66, 0x33CC99,
	0x33CCCC, 0x33CCFF, 0x33FF33, 0x33FF66, 0x33FF99, 0x33FFCC, 0x33FFFF, 0x660000,
	0x660033, 0x660066, 0x660099, 0x6600CC, 0x6600FF, 0x663300, 0x663333, 0x663366,
	0x663399, 0x6633CC, 0x6633FF, 0x666600, 0x666633, 0x666666, 0x666699, 0x6666CC,
	0x669900, 0x669933, 0x669966, 0x669999, 0x6699CC, 0x6699FF, 0x66CC00, 0x66CC33,
	0x66CC99, 0x66CCCC, 0x66CCFF, 0x66FF00, 0x66FF33, 0x66FF99, 0x66FFCC, 0xCC00FF,
	0xFF00CC, 0x999900, 0x993399, 0x990099, 0x9900CC, 0x990000, 0x993333, 0x990066,
	0x9933CC, 0x9900FF, 0x996600, 0x996633, 0x993366, 0x996699, 0x9966CC, 0x9933FF,
	0x999933, 0x999966, 0x999999, 0x9999CC, 0x9999FF, 0x99CC00, 0x99CC33, 0x66CC66,
	0x99CC99, 0x99CCCC, 0x99CCFF, 0x99FF00, 0x99FF33, 0x99CC66, 0x99FF99, 0x99FFCC,
	0x99FFFF, 0xCC0000, 0x990033, 0xCC0066, 0xCC0099, 0xCC00CC, 0x993300, 0xCC3333,
	0xCC3366, 0xCC3399, 0xCC33CC, 0xCC33FF, 0xCC6600, 0xCC6633, 0x996666, 0xCC6699,
	0xCC66CC, 0x9966FF, 0xCC9900, 0xCC9933, 0xCC9966, 0xCC9999, 0xCC99CC, 0xCC99FF,
	0xCCCC00, 0xCCCC33, 0xCCCC66, 0xCCCC99, 0xCCCCCC, 0xCCCCFF, 0xCCFF00, 0xCCFF33,
	0x99FF66, 0xCCFF99, 0xCCFFCC, 0xCCFFFF, 0xCC0033, 0xFF0066, 0xFF0099, 0xCC3300,
	0xFF3333, 0xFF3366, 0xFF3399, 0xFF33CC, 0xFF33FF, 0xFF6600, 0xFF6633, 0xCC6666,
	0xFF6699, 0xFF66CC, 0xCC66FF, 0xFF9900, 0xFF9933, 0xFF9966, 0xFF9999, 0xFF99CC,
	0xFF99FF, 0xFFCC00, 0xFFCC33, 0xFFCC66, 0xFFCC99, 0xFFCCCC, 0xFFCCFF, 0xFFFF33,
	0xCCFF66, 0xFFFF99, 0xFFFFCC, 0x6666FF, 0x66FF66, 0x66FFFF, 0xFF6666, 0xFF66FF,
	0xFFFF66, 0xC1C1C1, 0x5F5F5F, 0x777777, 0x868686, 0x969696, 0xCBCBCB, 0xB2B2B2,
	0xD7D7D7, 0xDDDDDD, 0xE3E3E3, 0xEAEAEA, 0xF1F1F1, 0xF8F8F8, 0xF0FBFF, 0xA4A0A0,
	0x808080, 0x0000FF, 0x00FF00, 0x00FFFF, 0xFF0000, 0xFF00FF, 0xFFFF00, 0xFFFFFF
};
int default_palette_idx [RGB_MAX+1] = {
	0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,  12,  13,  14,  15,
	16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
	32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,
	48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,
	64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
	80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
	96,  97,  98,  99,  100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
	112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
	128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
	144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
	160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
	176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
	192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
	208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
	224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
	240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
};

/*
* Bytes-per-pixel, for readability:
*/
#define BPP1    1
#define BPP2    2
#define BPP3    3
#define BPP4    4

#if defined (_MACINTOSH) && defined (_DEBUG)
#pragma global_optimizer on
#endif

/*
* Convert a value in the range of [-1,1],
* to a new range [l,h]; with a middle value equal to m.
*/
static double chrange (double x, double l, double m, double h)
{
	if (x >= 0.) {
		if (x > 1.) x = 1.;
		x = m + (h - m) * x;
	} else {
		if (x < -1.) x = -1.;
		x = m + (m - l) * x;
	}
	return x;
}

/*
* Checks if variable is signicantly different from zero.
*/
static int is (double val)
{
	return fabs(val) > 0.01;    /* < 1% is not considered a change */
}


/*
* Returns current state of "from/to I420" converters.
* Use:
*  void GetSrcI420Colors (float *brightness, float *contrast, float *saturation, float *hue);
* Output:
*  brightness - brightness adjustment [-1,1], 0 - default;
*  contrast   - contrast adjustment   [-1,1], 0 - default;
*  saturation - saturation adjustment [-1,1], 0 - default;
*  hue        - hue adjustment        [-1,1], 0 - default;
* Returns:
*  none.
*/
void GetSrcI420Colors (float *brightness, float *contrast, float *saturation, float *hue)
{
	if (brightness && contrast && saturation && hue)
	{
		*brightness = cur_brightness;
		*contrast   = cur_contrast;
		*saturation = cur_saturation;
		*hue	    = cur_hue;
	}
}

/*
* Initializes "from/to I420" converters.
* Use:
*  void SetSrcI420Colors (float brightness, float contrast, float saturation, float hue);
*  void SetDestI420Colors (float brightness, float contrast, float saturation, float hue);
* Input:
*  brightness - brightness adjustment [-1,1], 0 - default;
*  contrast   - contrast adjustment   [-1,1], 0 - default;
*  saturation - saturation adjustment [-1,1], 0 - default;
*  hue        - hue adjustment        [-1,1], 0 - default;
* Returns:
*  none.
*/
void SetSrcI420Colors (float brightness, float contrast, float saturation, float hue)
{
	/* check if we need to generate new color conversion tables: */
	if (!color_conversion_tables_inited  ||
		is (cur_brightness - brightness) ||
		is (cur_contrast - contrast)     ||
		is (cur_saturation - saturation) ||
		is (cur_hue - hue)) {

			double alpha, beta, gamma, kappa, lambda;
			double cos_alpha, xi_sin_alpha, minus_zeta_sin_alpha;
			register int i;

			/* hue: */
			alpha = chrange (hue, ALPHA_MIN, ALPHA_MED, ALPHA_MAX);
			cos_alpha = cos (alpha);
			xi_sin_alpha = XI * sin (alpha);
			minus_zeta_sin_alpha = -ZETA * sin (alpha);
			is_alpha = is (cur_hue = hue);

			/* saturation: */
			beta = chrange (saturation, BETA_MIN, BETA_MED, BETA_MAX);
			is_beta = is (cur_saturation = saturation);

			/* brightness: */
			gamma = chrange (brightness, GAMMA_MIN, GAMMA_MED, GAMMA_MAX);
			is_gamma = is (cur_brightness = brightness);

			/* contrast: */
			kappa = chrange (contrast, KAPPA_MIN, KAPPA_MED, KAPPA_MAX);
			lambda = LAMBDA (kappa);
			is_kappa = is (cur_contrast = contrast);

			/*
			* Check if we need to generate clip tables & default palette:
			*/
			if (!color_conversion_tables_inited) {

				/* Init clip tables. CLIP4/5/6 includes chop to 3/5/6 bits */
				for (i = -CLIPNEG; i < CLIPRNG + CLIPPOS; i++) {

					if (i < 0) {
						CLIP4[i] = 0;
						CLIP5[i] = 0;
						CLIP6[i] = 0;           /* clip */
						CLIP8[i] = 0;
					} else if (i > 255) {

						CLIP4[i] = 255 >> 4;
						CLIP5[i] = 255 >> 3;
						CLIP6[i] = 255 >> 2;    /* clip */
						CLIP8[i] = 255;
					} else {
						CLIP4[i] = i >> 4;      /* chop to 4 bits */
						CLIP5[i] = i >> 3;      /* chop to 5 bits */
						CLIP6[i] = i >> 2;      /* chop to 6 bits */
						CLIP8[i] = i;           /* leave at 8 bits */
					}
				}

				/* square values: */
				for (i = -RGB_MAX; i <= RGB_MAX; i ++)
					SQ[i] = i * i;

				/* set default palette: */
				SetDestRGB8Palette (256, default_palette, default_palette_idx);

				/* set indicator: */
				color_conversion_tables_inited ++;
			}

			/*
			* Initialize color conversion tables.
			*/
			for (i = 0; i < 256; i++) {

				/* Y'Cr'Cb'->R'G'B' conversion tables: */
				double y = lambda + (i - CCIR601_YOFFSET) * kappa; /* adjust contrast */
				if (y < 0) y = 0; else if (y > CCIR601_YMAX) y = CCIR601_YMAX;
				ytab  [i] = INT(y * YCOEF * gamma);
				rvtab [i] = INT((i-CCIR601_VOFFSET) * cos_alpha * RVCOEF * beta * gamma);
				gvtab [i] = INT((i-CCIR601_VOFFSET) * GVCOEF * beta * gamma);
				bvtab [i] = INT((i-CCIR601_VOFFSET) * xi_sin_alpha * BUCOEF * beta * gamma);
				rutab [i] = INT((i-CCIR601_UOFFSET) * minus_zeta_sin_alpha * RVCOEF * beta * gamma);
				gutab [i] = INT((i-CCIR601_UOFFSET) * GUCOEF * beta * gamma);
				butab [i] = INT((i-CCIR601_UOFFSET) * cos_alpha * BUCOEF * beta * gamma);

				/* Y'Cr'Cb'->Y'Cr'Cb' conversion tables: */
				y = lambda + (i - CCIR601_YOFFSET) * kappa;
				_yytab [i] = CLIP8 [CCIR601_YOFFSET + INT(y * gamma)];
				_vvtab [i] = CCIR601_VOFFSET + INT((i-CCIR601_VOFFSET) * cos_alpha * beta * gamma);
				_uutab [i] = CCIR601_UOFFSET + INT((i-CCIR601_UOFFSET) * cos_alpha * beta * gamma);
				_vutab [i] = INT((i-CCIR601_UOFFSET) * minus_zeta_sin_alpha * beta * gamma);
				_uvtab [i] = INT((i-CCIR601_VOFFSET) * xi_sin_alpha * beta * gamma);
				if (!is_alpha) {
					_vvtab [i] = CLIP8 [_vvtab [i]];
					_uutab [i] = CLIP8 [_uutab [i]];
				}
			}
	}
}

void SetDestI420Colors (float brightness, float contrast, float saturation, float hue)
{
	/* Currently, all color adjustment parameters are ignored,
	* and tables will always be initialized for CCIR 601-2 - compliant
	* color conversion. */

	register int i, j;

	/* initialize y*tab[] tables: */
	for (i = 0; i <= RGB_MAX; i++) {
		yrtab [i] = INT((double)i * CCIR601_YRCOEF);
		ygtab [i] = INT((double)i * CCIR601_YGCOEF);
		ybtab [i] = INT((double)i * CCIR601_YBCOEF);
	}

	/* initialize yytab[]: */
	for (i = 0; i <= YMAX; i++) {
		j = INT((double)i * YSCALE);
		if (j > CCIR601_YMAX) j = CCIR601_YMAX;
		yytab [i] = j + CCIR601_YOFFSET;
	}

	/* initialize vrytab[]: */
	for (i = -VMIN; i <= VMAX; i++) {
		j = INT((double)i * VSCALE);
		if (j < -CCIR601_VMAX/2) j = -CCIR601_VMAX/2;
		if (j >  CCIR601_VMAX/2) j =  CCIR601_VMAX/2;
		vrytab [VMIN+i] = j + CCIR601_VOFFSET;
	}

	/* initialize ubytab[]: */
	for (i = -UMIN; i <= UMAX; i++) {
		j = INT((double)i * USCALE);
		if (j < -CCIR601_UMAX/2) j = -CCIR601_UMAX/2;
		if (j >  CCIR601_UMAX/2) j =  CCIR601_UMAX/2;
		ubytab [UMIN+i] = j + CCIR601_UOFFSET;
	}
}

/*
* Suggest palettes to use for 8-bit RGB formats.
* Use:
*  int SuggestSrcRGB8Palette (int nColors, unsigned int *lpRGBVals);
*  int SuggestDestRGB8Palette (int nColors, unsigned int *lpRGBVals);
* Input:
*  nColors - the number of existing colors in palette
*  lpRGBVals - RGB values for each palette entry
*  lpIndices - pixel values (palette indices)
* Returns:
*  >0, the total number of colors to be used, if success
*  -1, if error
*/
int SuggestSrcRGB8Palette (int nColors, unsigned int *lpRGBVals)
{
	return -1;    /* not implemented yet... */
}

int SuggestDestRGB8Palette (int nColors, unsigned int *lpRGBVals)
{
	unsigned int rgb;
	int r, g, b, i, j, delta;

	/* determine the quanization step size: */
	if      (256 - nColors >= 6*6*6)    delta = 0x33;   /* 6x6x6 = 216 */
	else if (256 - nColors >= 5*5*5)    delta = 0x40;   /* 5x5x5 = 125 */
	else if (256 - nColors >= 4*4*4)    delta = 0x55;   /* 4x4x4 = 64  */
	else return nColors;

	/* complement the set of palette entries with ours: */
	i = nColors;
	for (r = 0; r <= 256; r += delta) { if (r == 256) r = 255;
	for (g = 0; g <= 256; g += delta) { if (g == 256) g = 255;
	for (b = 0; b <= 256; b += delta) { if (b == 256) b = 255;

	/* form palette entry: */
	rgb = b | (g << 8) | (r << 16);

	/* check if we had this color before: */
	for (j = 0; j < nColors; j ++)  if (lpRGBVals[j] == rgb) goto skip;

	/* add color: */
	lpRGBVals[i] = rgb;
	i ++;

skip:   ;
	}}}

	/* return total # of entries used: */
	return i;
}

/*
* Set palettes to use for 8-bit RGB formats.
* Use:
*  int SetSrcRGB8Palette (int nColors, unsigned int *lpRGBVals, int *lpIndices);
*  int SetDestRGB8Palette (int nColors, unsigned int *lpRGBVals, int *lpIndices);
* Input:
*  nColors - the number of colors in palette
*  lpRGBVals - RGB values for each palette entry
*  lpIndices - pixel values (palette indices)
* Returns:
*  >0, the total number of colors set, if success
*  -1, if error
*/
int SetSrcRGB8Palette (int nColors, unsigned int *lpRGBVals, int *lpIndices)
{
	return -1;    /* not implemented yet... */
}

int SetDestRGB8Palette (int nColors, unsigned int *lpRGBVals, int *lpIndices)
{
	register unsigned int r, g, b, delta = 1U << 4;

	/* perform the minimum energy mismatch mapping: */
	for (r = 0; r < 256; r += delta) {
		for (g = 0; g < 256; g += delta) {
			for (b = 0; b < 256; b += delta) {

				/* initialize search: */
				int idx, match_idx = 0;
				unsigned int j, diff, match_diff;
				j = lpRGBVals[0];
				match_diff =
					SQ[(int)(r - ((j >> 0)  & 0xFF))] +
					SQ[(int)(g - ((j >> 8)  & 0xFF))] +
					SQ[(int)(b - ((j >> 16) & 0xFF))];

				/* find minimum: */
				for (idx = 1; idx < nColors; idx ++) {
					j = lpRGBVals[idx];
					diff =
						SQ[(int)(r - ((j >> 0)  & 0xFF))] +
						SQ[(int)(g - ((j >> 8)  & 0xFF))] +
						SQ[(int)(b - ((j >> 16) & 0xFF))];

					if (diff < match_diff) {
						match_idx = idx;
						match_diff = diff;
					}
				}

				/* store the result: */
				pmap[(b >> 4) | g | (r << 4)] = lpIndices[match_idx];
			}}}

	return nColors;
}

/*
* Checks format conversion parameters.
* Use:
*  int chk_args (unsigned char *dest_ptr, int dest_width, int dest_height,
*      int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
*      unsigned char *src_ptr, int src_width, int src_height,
*      int src_pitch, int src_x, int src_y, int src_dx, int src_dy,
*      int *p_scale_x, int *p_scale_y);
* Input:
*  dest_ptr - pointer to a destination buffer
*  dest_width, dest_height - width/height of the destination image (pixels)
*  dest_pitch - pitch of the dest. buffer (in bytes; <0 - if bottom up image)
*  dest_x, dest_y, dest_dx, dest_dy - destination rectangle (pixels)
*  src_ptr - pointer to an input image
*  src_width, src_height - width/height of the input image (pixels)
*  src_pitch - pitch of the source buffer (in bytes; <0 - if bottom up image)
*  src_x, src_y, src_dx, src_dy - source rectangle (pixels)
* Output:
*  p_scale_x, p_scale_y - scale factors for x,y axes
*      (currently only 1:1, and 2:1 scale factors are allowed)
* Returns:
*  0 - if success; -1 if failure.
*/
static int
chk_args (unsigned char *dest_ptr, int dest_width, int dest_height,
		  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
		  unsigned char *src_ptr, int src_width, int src_height,
		  int src_pitch, int src_x, int src_y, int src_dx, int src_dy,
		  int *p_scale_x, int *p_scale_y)
{
	/* alignments: */
	if (((unsigned)dest_ptr & 3) || (dest_pitch & 3) ||
		((unsigned)src_ptr  & 3) || (src_pitch  & 3) ||
		/* image sizes: */
		dest_width <= 0 || dest_height <= 0 ||
		src_width  <= 0 || src_height  <= 0 ||
		/* rectangles: */
		dest_x < 0 || dest_y < 0 || dest_dx <= 0 || dest_dy <= 0 ||
		src_x  < 0 || src_y  < 0 || src_dx  <= 0 || src_dy  <= 0 ||
		/* overlaps: */
		dest_width < dest_x + dest_dx || dest_height < dest_y + dest_dy ||
		src_width  < src_x  + src_dx  || src_height  < src_y  + src_dy)
		goto fail;

	/* scale factors: */
	if (dest_dx == src_dx)          *p_scale_x = 1;
	else if (dest_dx == 2 * src_dx) *p_scale_x = 2;
	else goto fail;
	if (dest_dy == src_dy)          *p_scale_y = 1;
	else if (dest_dy == 2 * src_dy) *p_scale_y = 2;
	else goto fail;

	/* success: */
	return 1;

	/* failure: */
fail:
	return 0;
}

static int adjust_range (int *z1, int *dz1, int *z2, int *dz2, int inc2)
{
	/* skip odd start pixel: */
	if (*z1 & 1) {
		*z1 += 1;
		*dz1 -= 1;
		*z2 += inc2;
		*dz2 -= inc2;
	}
	/* clip the range: */
	if (*dz1 & 1) {
		*dz1 -= 1;
		*dz2 -= inc2;
	}
	return (*dz1 > 0 && *dz2 > 0);
}

/*
* Format-conversion routines.
* Use:
*  int XXXXtoYYYYEx (unsigned char *dest_ptr, int dest_width, int dest_height,
*      int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
*      unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
*      int src_x, int src_y, int src_dx, int src_dy);
* Input:
*  dest_ptr - pointer to a destination buffer
*  dest_width, dest_height - width/height of the destination image (pixels)
*  dest_pitch - pitch of the dest. buffer (in bytes; <0 - if bottom up image)
*  dest_x, dest_y, dest_dx, dest_dy - destination rectangle (pixels)
*  src_ptr - pointer to an input image
*  src_width, src_height - width/height of the input image (pixels)
*  src_pitch - pitch of the source buffer (in bytes; <0 - if bottom up image)
*  src_x, src_y, src_dx, src_dy - source rectangle (pixels)
* Returns:
*  0 - if success; -1 if failure.
* Notes:
*  a) In all cases, pointers to the source and destination buffers must be
*     DWORD aligned, and both pitch parameters must be multiple of 4!!!
*  b) Converters that deal with YUV 4:2:2, or 4:2:0 formats may also require
*     rectangle parameters (x,y,dx,dy) to be multiple of 2. Failure to provide
*     aligned rectangles will result in partially converted image.
*  c) Currently only scale factors of 1:1 and 2:1 are supported; if the rates
*     dest_dx/src_dx & dest_dy/src_dy are neither 1, or 2, the converters
*     will fail.
*/


/*
* I420toI420() converter:
*/
int I420toI420 (unsigned char *dest_ptr, int dest_width, int dest_height,
				int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* remove odd destination pixels: */
	if (!adjust_range (&dest_x, &dest_dx, &src_x, &src_dx, scale_x) ||
		!adjust_range (&dest_y, &dest_dy, &src_y, &src_dy, scale_y))
		return 0;

	/* check if we have matching chroma components: */
	if ((src_x & 1) || (src_y & 1))
		return -1;                          /* can't shift chromas */

	/* check if bottop-up images: */
	if (dest_pitch <= 0 || src_pitch <= 0)
		return -1;                          /* not supported for this format */

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* check if no color adjustmenst: */
		if (!(is_alpha | is_beta | is_gamma | is_kappa)) {

			/* no color adjustments: */
			unsigned char *s, *d;
			int src_uv_offs, dest_uv_offs;
			register int i;

			/* copy Y plane: */
			s = src_ptr + src_x + src_y * src_pitch;
			d = dest_ptr + dest_x + dest_y * dest_pitch;
			for (i = 0; i < dest_dy; i ++) {
				memcpy (d, s, dest_dx); /* Flawfinder: ignore */
				s += src_pitch;
				d += dest_pitch;
			}

			/* get Cr/Cb offsets: */
			src_uv_offs = src_height * src_pitch / 4;
			dest_uv_offs = dest_height * dest_pitch / 4;

			/* copy Cr/Cb planes: */
			s = (src_ptr + src_height * src_pitch) + src_x/2 + src_y/2 * src_pitch/2;
			d = (dest_ptr + dest_height * dest_pitch) + dest_x/2 + dest_y/2 * dest_pitch/2;
			for (i = 0; i < dest_dy/2; i ++) {
				memcpy (d, s, dest_dx/2); /* Flawfinder: ignore */
				memcpy (d + dest_uv_offs, s + src_uv_offs, dest_dx/2); /* Flawfinder: ignore */
				s += src_pitch/2;
				d += dest_pitch/2;
			}

		} else {

			/* adjust colors: */
			unsigned char *s, *d;
			int src_uv_offs, dest_uv_offs;
			register int i, j;

			/* convert Y plane: */
			s = src_ptr + src_x + src_y * src_pitch;
			d = dest_ptr + dest_x + dest_y * dest_pitch;
			for (i = 0; i < dest_dy; i ++) {

				/* convert pixels: */
				for (j = 0; j < dest_dx; j ++)
					d[j] = _yytab[s[j]];

				s += src_pitch;
				d += dest_pitch;
			}

			/* get Cr/Cb offsets: */
			src_uv_offs = src_height * src_pitch / 4;
			dest_uv_offs = dest_height * dest_pitch / 4;

			/* get chroma pointers: */
			s = (src_ptr + src_height * src_pitch) + src_x/2 + src_y/2 * src_pitch/2;
			d = (dest_ptr + dest_height * dest_pitch) + dest_x/2 + dest_y/2 * dest_pitch/2;

			/* check if no hue adjustment: */
			if (!is_alpha) {

				/* no chroma rotation: */
				for (i = 0; i < dest_dy/2; i ++) {

					/* convert pixels: */
					for (j = 0; j < dest_dx/2; j ++) {
						d[j] = _vvtab[s[j]];
						d[j + dest_uv_offs] = _uutab[s[j + src_uv_offs]];
					}

					s += src_pitch/2;
					d += dest_pitch/2;
				}

			} else {

				/* adjust hue: */
				for (i = 0; i < dest_dy/2; i ++) {

					/* convert pixels: */
					for (j = 0; j < dest_dx/2; j ++) {
						register unsigned v = s[j], u = s[j + src_uv_offs];
						d[j] = CLIP8[_vvtab[v] + _vutab[u]];
						d[j + dest_uv_offs] = CLIP8[_uutab[u] + _uvtab[v]];
					}

					s += src_pitch/2;
					d += dest_pitch/2;
				}
			}
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

/*
* I420toYV12() converter:
*/
int I420toYV12 (unsigned char *dest_ptr, int dest_width, int dest_height,
				int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* remove odd destination pixels: */
	if (!adjust_range (&dest_x, &dest_dx, &src_x, &src_dx, scale_x) ||
		!adjust_range (&dest_y, &dest_dy, &src_y, &src_dy, scale_y))
		return 0;

	/* check if we have matching chroma components: */
	if ((src_x & 1) || (src_y & 1))
		return -1;                          /* can't shift chromas */

	/* check if bottop-up images: */
	if (dest_pitch <= 0 || src_pitch <= 0)
		return -1;                          /* not supported for this format */

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* check if no color adjustments: */
		if (!(is_alpha | is_beta | is_gamma | is_kappa)) {

			/* no color adjustments: */
			unsigned char *s, *d;
			int src_uv_offs, dest_uv_offs;
			register int i;

			/* copy Y plane: */
			s = src_ptr + src_x + src_y * src_pitch;
			d = dest_ptr + dest_x + dest_y * dest_pitch;
			for (i = 0; i < dest_dy; i ++) {
				memcpy (d, s, dest_dx); /* Flawfinder: ignore */
				s += src_pitch;
				d += dest_pitch;
			}

			/* get Cr/Cb offsets: */
			src_uv_offs = src_height * src_pitch / 4;
			dest_uv_offs = dest_height * dest_pitch / 4;

			/* copy Cr/Cb planes: */
			s = (src_ptr + src_height * src_pitch) + src_x/2 + src_y/2 * src_pitch/2;
			d = (dest_ptr + dest_height * dest_pitch) + dest_x/2 + dest_y/2 * dest_pitch/2;
			for (i = 0; i < dest_dy/2; i ++) {
				memcpy (d, s + src_uv_offs, dest_dx/2); /* Flawfinder: ignore */
				memcpy (d + dest_uv_offs, s, dest_dx/2); /* Flawfinder: ignore */
				s += src_pitch/2;
				d += dest_pitch/2;
			}

		} else {

			/* adjust colors: */
			unsigned char *s, *d;
			int src_uv_offs, dest_uv_offs;
			register int i, j;

			/* convert Y plane: */
			s = src_ptr + src_x + src_y * src_pitch;
			d = dest_ptr + dest_x + dest_y * dest_pitch;
			for (i = 0; i < dest_dy; i ++) {

				/* convert pixels: */
				for (j = 0; j < dest_dx; j ++)
					d[j] = _yytab[s[j]];

				s += src_pitch;
				d += dest_pitch;
			}

			/* get Cr/Cb offsets: */
			src_uv_offs = src_height * src_pitch / 4;
			dest_uv_offs = dest_height * dest_pitch / 4;

			/* get chroma pointers: */
			s = (src_ptr + src_height * src_pitch) + src_x/2 + src_y/2 * src_pitch/2;
			d = (dest_ptr + dest_height * dest_pitch) + dest_x/2 + dest_y/2 * dest_pitch/2;

			/* check if no hue adjustment: */
			if (!is_alpha) {

				/* no chroma rotation: */
				for (i = 0; i < dest_dy/2; i ++) {

					/* convert pixels: */
					for (j = 0; j < dest_dx/2; j ++) {
						d[j] = _vvtab[s[j + src_uv_offs]];
						d[j + dest_uv_offs] = _uutab[s[j]];
					}

					s += src_pitch/2;
					d += dest_pitch/2;
				}

			} else {

				/* adjust hue: */
				for (i = 0; i < dest_dy/2; i ++) {

					/* convert pixels: */
					for (j = 0; j < dest_dx/2; j ++) {
						register unsigned v = s[j + src_uv_offs], u = s[j];
						d[j] = CLIP8[_vvtab[v] + _vutab[u]];
						d[j + dest_uv_offs] = CLIP8[_uutab[u] + _uvtab[v]];
					}

					s += src_pitch/2;
					d += dest_pitch/2;
				}
			}
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

/*
* I420toYUY2() converter:
*/
int I420toYUY2 (unsigned char *dest_ptr, int dest_width, int dest_height,
				int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* remove odd destination columns: */
	if (!adjust_range (&dest_x, &dest_dx, &src_x, &src_dx, scale_x))
		return 0;

	/* check if we have misaligned input: */
	if (src_x & 1)
		return -1;                          /* can't shift chromas */

	/* check if bottop-up images: */
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;
	if (src_pitch <= 0) return -1;          /* not supported */

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* check if no color adjustments: */
		if (!(is_alpha | is_beta | is_gamma | is_kappa)) {

			/* no color adjustments: */
			unsigned char *sy, *sv, *su, *d;
			register int i, j;

			/* get pointers: */
			sy = src_ptr + src_x + src_y * src_pitch;           /* luma offset */
			su = src_ptr + src_height * src_pitch + (src_x/2 + src_y/2 * src_pitch);
			sv = su + src_height * src_pitch / 4;
			d  = dest_ptr + dest_x * 2 + dest_y * dest_pitch;   /* 2 bytes/pixel */

			/* process top line (if chroma is not pairable): */
			if (dest_y & 1) {
				for (j = 0; j < dest_dx/2; j ++)
					*(unsigned int *)(d + j*4) = sy[j*2] | (su[j] << 8) | (sy[j*2+1] << 16) | (sv[j] << 24);
				sy += src_pitch;
				su += src_pitch/2;
				sv += src_pitch/2;
				d  += dest_pitch;
				dest_dy --;
			}
			/* the main loop (processes two lines a time): */
			for (i = 0; i < dest_dy/2; i ++) {
				for (j = 0; j < dest_dx/2; j ++)
					*(unsigned int *)(d + j*4) = sy[j*2] | (su[j] << 8) | (sy[j*2+1] << 16) | (sv[j] << 24);
				sy += src_pitch;
				d  += dest_pitch;
				for (j = 0; j < dest_dx/2; j ++)
					*(unsigned int *)(d + j*4) = sy[j*2] | (su[j] << 8) | (sy[j*2+1] << 16) | (sv[j] << 24);
				sy += src_pitch;
				su += src_pitch/2;
				sv += src_pitch/2;
				d  += dest_pitch;
			}
			/* process the last line (if dy is odd): */
			if (dest_dy & 1) {
				for (j = 0; j < dest_dx/2; j ++)
					*(unsigned int *)(d + j*4) = sy[j*2] | (su[j] << 8) | (sy[j*2+1] << 16) | (sv[j] << 24);
			}

		} else

			/* check if no hue adjustment: */
			if (!is_alpha) {

				/* no chroma rotation: */
				unsigned char *sy, *sv, *su, *d;
				register int i, j;

				/* get pointers: */
				sy = src_ptr + src_x + src_y * src_pitch;           /* luma offset */
				su = src_ptr + src_height * src_pitch + (src_x/2 + src_y/2 * src_pitch);
				sv = su + src_height * src_pitch / 4;
				d  = dest_ptr + dest_x * 2 + dest_y * dest_pitch;   /* 2 bytes/pixel */

				/* process top line (if chroma is not pairable): */
				if (dest_y & 1) {
					for (j = 0; j < dest_dx/2; j ++)
						*(unsigned int *)(d + j*4) = _yytab[sy[j*2]] | (_uutab[su[j]] << 8) | (_yytab[sy[j*2+1]] << 16) | (_vvtab[sv[j]] << 24);
					sy += src_pitch;
					su += src_pitch/2;
					sv += src_pitch/2;
					d  += dest_pitch;
					dest_dy --;
				}
				/* the main loop (processes two lines a time): */
				for (i = 0; i < dest_dy/2; i ++) {
					for (j = 0; j < dest_dx/2; j ++)
						*(unsigned int *)(d + j*4) = _yytab[sy[j*2]] | (_uutab[su[j]] << 8) | (_yytab[sy[j*2+1]] << 16) | (_vvtab[sv[j]] << 24);
					sy += src_pitch;
					d  += dest_pitch;
					for (j = 0; j < dest_dx/2; j ++)
						*(unsigned int *)(d + j*4) = _yytab[sy[j*2]] | (_uutab[su[j]] << 8) | (_yytab[sy[j*2+1]] << 16) | (_vvtab[sv[j]] << 24);
					sy += src_pitch;
					su += src_pitch/2;
					sv += src_pitch/2;
					d  += dest_pitch;
				}
				/* process the last line (if dy is odd): */
				if (dest_dy & 1) {
					for (j = 0; j < dest_dx/2; j ++)
						*(unsigned int *)(d + j*4) = _yytab[sy[j*2]] | (_uutab[su[j]] << 8) | (_yytab[sy[j*2+1]] << 16) | (_vvtab[sv[j]] << 24);
				}

			} else {

				/* the most complex case (w. hue adjustment): */
				unsigned char *sy, *sv, *su, *d;
				register int i, j, u, v;

				/* get pointers: */
				sy = src_ptr + src_x + src_y * src_pitch;           /* luma offset */
				su = src_ptr + src_height * src_pitch + (src_x/2 + src_y/2 * src_pitch/2);
				sv = su + src_height * src_pitch / 4;
				d  = dest_ptr + dest_x * 2 + dest_y * dest_pitch;   /* 2 bytes/pixel */

				/* process top line (if chroma is not pairable): */
				if (dest_y & 1) {
					for (j = 0; j < dest_dx/2; j ++) {
						v = CLIP8[_vvtab[sv[j]] + _vutab[su[j]]];
						u = CLIP8[_uutab[su[j]] + _uvtab[sv[j]]];
						*(unsigned int *)(d + j*4) = _yytab[sy[j*2]] | (u << 8) | (_yytab[sy[j*2+1]] << 16) | (v << 24);
					}
					sy += src_pitch;
					su += src_pitch/2;
					sv += src_pitch/2;
					d  += dest_pitch;
					dest_dy --;
				}
				/* the main loop (processes two lines a time): */
				for (i = 0; i < dest_dy/2; i ++) {
					for (j = 0; j < dest_dx/2; j ++) {
						v = CLIP8[_vvtab[sv[j]] + _vutab[su[j]]];
						u = CLIP8[_uutab[su[j]] + _uvtab[sv[j]]];
						*(unsigned int *)(d + j*4) = _yytab[sy[j*2]] | (u << 8) | (_yytab[sy[j*2+1]] << 16) | (v << 24);
						*(unsigned int *)(d + j*4 + dest_pitch) = _yytab[sy[j*2 + src_pitch]] | (u << 8) | (_yytab[sy[j*2+1+src_pitch]] << 16) | (v << 24);
					}
					sy += src_pitch*2;
					su += src_pitch/2;
					sv += src_pitch/2;
					d  += dest_pitch*2;
				}
				/* process the last line (if dy is odd): */
				if (dest_dy & 1) {
					for (j = 0; j < dest_dx/2; j ++) {
						v = CLIP8[_vvtab[sv[j]] + _vutab[su[j]]];
						u = CLIP8[_uutab[su[j]] + _uvtab[sv[j]]];
						*(unsigned int *)(d + j*4) = _yytab[sy[j*2]] | (u << 8) | (_yytab[sy[j*2+1]] << 16) | (v << 24);
					}
				}
			}
			return 0;
	}

	/* conversion is not supported */
	return -1;
}

/*
* I420toUYVY() converter:
*/
int I420toUYVY (unsigned char *dest_ptr, int dest_width, int dest_height,
				int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* remove odd destination columns: */
	if (!adjust_range (&dest_x, &dest_dx, &src_x, &src_dx, scale_x))
		return 0;

	/* check if we have misaligned input: */
	if (src_x & 1)
		return -1;                          /* can't shift chromas */

	/* check if bottop-up images: */
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;
	if (src_pitch <= 0) return -1;          /* not supported */

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* check if no color adjustments: */
		if (!(is_alpha | is_beta | is_gamma | is_kappa)) {

			/* no color adjustments: */
			unsigned char *sy, *sv, *su, *d;
			register int i, j;

			/* get pointers: */
			sy = src_ptr + src_x + src_y * src_pitch;           /* luma offset */
			su = src_ptr + src_height * src_pitch + (src_x/2 + src_y/2 * src_pitch);
			sv = su + src_height * src_pitch / 4;
			d  = dest_ptr + dest_x * 2 + dest_y * dest_pitch;   /* 2 bytes/pixel */

			/* process top line (if chroma is not pairable): */
			if (dest_y & 1) {
				for (j = 0; j < dest_dx/2; j ++)
					*(unsigned int *)(d + j*4) = su[j] | (sy[j*2] << 8) | (sv[j] << 16) | (sy[j*2+1] << 24);
				sy += src_pitch;
				su += src_pitch/2;
				sv += src_pitch/2;
				d  += dest_pitch;
				dest_dy --;
			}
			/* the main loop (processes two lines a time): */
			for (i = 0; i < dest_dy/2; i ++) {
				for (j = 0; j < dest_dx/2; j ++)
					*(unsigned int *)(d + j*4) = su[j] | (sy[j*2] << 8) | (sv[j] << 16) | (sy[j*2+1] << 24);
				sy += src_pitch;
				d  += dest_pitch;
				for (j = 0; j < dest_dx/2; j ++)
					*(unsigned int *)(d + j*4) = su[j] | (sy[j*2] << 8) | (sv[j] << 16) | (sy[j*2+1] << 24);
				sy += src_pitch;
				su += src_pitch/2;
				sv += src_pitch/2;
				d  += dest_pitch;
			}
			/* process the last line (if dy is odd): */
			if (dest_dy & 1) {
				for (j = 0; j < dest_dx/2; j ++)
					*(unsigned int *)(d + j*4) = su[j] | (sy[j*2] << 8) | (sv[j] << 16) | (sy[j*2+1] << 24);
			}

		} else

			/* check if no hue adjustment: */
			if (!is_alpha) {

				/* no chroma rotation: */
				unsigned char *sy, *sv, *su, *d;
				register int i, j;

				/* get pointers: */
				sy = src_ptr + src_x + src_y * src_pitch;           /* luma offset */
				su = src_ptr + src_height * src_pitch + (src_x/2 + src_y/2 * src_pitch);
				sv = su + src_height * src_pitch / 4;
				d  = dest_ptr + dest_x * 2 + dest_y * dest_pitch;   /* 2 bytes/pixel */

				/* process top line (if chroma is not pairable): */
				if (dest_y & 1) {
					for (j = 0; j < dest_dx/2; j ++)
						*(unsigned int *)(d + j*4) = _uutab[su[j]] | (_yytab[sy[j*2]] << 8) | (_vvtab[sv[j]] << 16) | (_yytab[sy[j*2+1]] << 24);
					sy += src_pitch;
					su += src_pitch/2;
					sv += src_pitch/2;
					d  += dest_pitch;
					dest_dy --;
				}
				/* the main loop (processes two lines a time): */
				for (i = 0; i < dest_dy/2; i ++) {
					for (j = 0; j < dest_dx/2; j ++)
						*(unsigned int *)(d + j*4) = _uutab[su[j]] | (_yytab[sy[j*2]] << 8) | (_vvtab[sv[j]] << 16) | (_yytab[sy[j*2+1]] << 24);
					sy += src_pitch;
					d  += dest_pitch;
					for (j = 0; j < dest_dx/2; j ++)
						*(unsigned int *)(d + j*4) = _uutab[su[j]] | (_yytab[sy[j*2]] << 8) | (_vvtab[sv[j]] << 16) | (_yytab[sy[j*2+1]] << 24);
					sy += src_pitch;
					su += src_pitch/2;
					sv += src_pitch/2;
					d  += dest_pitch;
				}
				/* process the last line (if dy is odd): */
				if (dest_dy & 1) {
					for (j = 0; j < dest_dx/2; j ++)
						*(unsigned int *)(d + j*4) = _uutab[su[j]] | (_yytab[sy[j*2]] << 8) | (_vvtab[sv[j]] << 16) | (_yytab[sy[j*2+1]] << 24);
				}

			} else {

				/* the most complex case (w. hue adjustement): */
				unsigned char *sy, *sv, *su, *d;
				register int i, j, u, v;

				/* get pointers: */
				sy = src_ptr + src_x + src_y * src_pitch;           /* luma offset */
				su = src_ptr + src_height * src_pitch + (src_x/2 + src_y/2 * src_pitch/2);
				sv = su + src_height * src_pitch / 4;
				d  = dest_ptr + dest_x * 2 + dest_y * dest_pitch;   /* 2 bytes/pixel */

				/* process top line (if chroma is not pairable): */
				if (dest_y & 1) {
					for (j = 0; j < dest_dx/2; j ++) {
						v = CLIP8[_vvtab[sv[j]] + _vutab[su[j]]];
						u = CLIP8[_uutab[su[j]] + _uvtab[sv[j]]];
						*(unsigned int *)(d + j*4) = u | (_yytab[sy[j*2]] << 8) | (v << 16) | (_yytab[sy[j*2+1]] << 24);
					}
					sy += src_pitch;
					su += src_pitch/2;
					sv += src_pitch/2;
					d  += dest_pitch;
					dest_dy --;
				}
				/* the main loop (processes two lines a time): */
				for (i = 0; i < dest_dy/2; i ++) {
					for (j = 0; j < dest_dx/2; j ++) {
						v = CLIP8[_vvtab[sv[j]] + _vutab[su[j]]];
						u = CLIP8[_uutab[su[j]] + _uvtab[sv[j]]];
						*(unsigned int *)(d + j*4) = u | (_yytab[sy[j*2]] << 8) | (v << 16) | (_yytab[sy[j*2+1]] << 24);
						*(unsigned int *)(d + j*4 + dest_pitch) = u | (_yytab[sy[j*2 + src_pitch]] << 8) | (v << 16) | (_yytab[sy[j*2+1 + src_pitch]] << 24);
					}
					sy += src_pitch*2;
					su += src_pitch/2;
					sv += src_pitch/2;
					d  += dest_pitch*2;
				}
				/* process the last line (if dy is odd): */
				if (dest_dy & 1) {
					for (j = 0; j < dest_dx/2; j ++) {
						v = CLIP8[_vvtab[sv[j]] + _vutab[su[j]]];
						u = CLIP8[_uutab[su[j]] + _uvtab[sv[j]]];
						*(unsigned int *)(d + j*4) = u | (_yytab[sy[j*2]] << 8) | (v << 16) | (_yytab[sy[j*2+1]] << 24);
					}
				}
			}
			return 0;
	}

	/* conversion is not supported */
	return -1;
}

/*
* I420->RGB* double-line converters:
*/
static void dblineI420toRGB32 (unsigned char *d1, unsigned char *d2, int dest_x,
							   unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
							   int src_x, int dx)
{
	register int y1, y2, rv, guv, bu;
	register int i;

	/* convert first 2x1 block: */
	if (src_x & 1) {

		bu = butab[su[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		rv = rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + bu])       |
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + rv]  << 16);

		/* second line BGR0 */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + bu])       |
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + rv]  << 16);

		sy1 += 1; sy2 += 1;
		su += 1; sv += 1;           /* shift luma !!! */
		d1 += BPP4; d2 += BPP4;
		dx --;
	}

	/* convert all integral 2x2 blocks: */
	for (i = 0; i < dx/2; i ++) {

		bu = butab[su[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		rv = rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + bu])       |
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + rv]  << 16);

		/* second line BGR0 */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + bu])       |
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + rv]  << 16);

		/* 2nd row: */
		y1 = ytab[sy1[1]];
		y2 = ytab[sy2[1]];

		/* first line BGR0 */
		*(unsigned int *)(d1+BPP4) =
			(CLIP8[y1 + bu])       |
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + rv]  << 16);

		/* second line BGR0 */
		*(unsigned int *)(d2+BPP4) =
			(CLIP8[y2 + bu])       |
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + rv]  << 16);

		/* next 2x2 block */
		sy1 += 2; sy2 += 2;
		su += 1; sv += 1;
		d1 += 2*BPP4; d2 += 2*BPP4;
	}

	/* convert the last 2x1 block: */
	if (dx & 1) {

		bu = butab[su[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		rv = rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + bu])       |
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + rv]  << 16);

		/* second line BGR0 */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + bu])       |
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + rv]  << 16);
	}
}

static void dblineI420toRGB32alpha (unsigned char *d1, unsigned char *d2, int dest_x,
									unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
									int src_x, int dx)
{
	register int y1, y2, ruv, guv, buv;
	register int i;

	/* convert first 2x1 block: */
	if (src_x & 1) {

		buv = butab[su[0]] + bvtab[sv[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		ruv = rutab[su[0]] + rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + buv])      |
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + ruv] << 16);

		/* second line BGR0 */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + buv])      |
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + ruv] << 16);

		sy1 += 1; sy2 += 1;
		su += 1; sv += 1;           /* shift luma !!! */
		d1 += BPP4; d2 += BPP4;
		dx --;
	}

	/* convert all integral 2x2 blocks: */
	for (i = 0; i < dx/2; i ++) {

		buv = butab[su[0]] + bvtab[sv[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		ruv = rutab[su[0]] + rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + buv])      |
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + ruv] << 16);

		/* second line BGR0 */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + buv])      |
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + ruv] << 16);

		y1 = ytab[sy1[1]];
		y2 = ytab[sy2[1]];

		/* first line BGR0 */
		*(unsigned int *)(d1+BPP4) =
			(CLIP8[y1 + buv])      |
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + ruv] << 16);

		/* second line BGR0 */
		*(unsigned int *)(d2+BPP4) =
			(CLIP8[y2 + buv])      |
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + ruv] << 16);

		/* next 2x2 block */
		sy1 += 2; sy2 += 2;
		su += 1; sv += 1;
		d1 += 2*BPP4; d2 += 2*BPP4;
	}

	/* convert last 2x1 block: */
	if (dx & 1) {

		buv = butab[su[0]] + bvtab[sv[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		ruv = rutab[su[0]] + rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + buv])      |
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + ruv] << 16);

		/* second line BGR0 */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + buv])      |
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + ruv] << 16);
	}
}

static void dblineI420toBGR32 (unsigned char *d1, unsigned char *d2, int dest_x,
							   unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
							   int src_x, int dx)
{
	register int y1, y2, rv, guv, bu;
	register int i;

	/* convert first 2x1 block: */
	if (src_x & 1) {

		bu = butab[su[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		rv = rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + bu]  << 16)|
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + rv]  << 0);

		/* second line BGR0 */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + bu]  << 16)|
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + rv]  << 0);

		sy1 += 1; sy2 += 1;
		su += 1; sv += 1;           /* shift luma !!! */
		d1 += BPP4; d2 += BPP4;
		dx --;
	}

	/* convert all integral 2x2 blocks: */
	for (i = 0; i < dx/2; i ++) {

		bu = butab[su[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		rv = rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + bu]  << 16)|
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + rv]  << 0);

		/* second line BGR0 */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + bu]  << 16)|
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + rv]  << 0);

		/* 2nd row: */
		y1 = ytab[sy1[1]];
		y2 = ytab[sy2[1]];

		/* first line BGR0 */
		*(unsigned int *)(d1+BPP4) =
			(CLIP8[y1 + bu]  << 16)|
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + rv]  << 0);

		/* second line BGR0 */
		*(unsigned int *)(d2+BPP4) =
			(CLIP8[y2 + bu]  << 16)|
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + rv]  << 0);

		/* next 2x2 block */
		sy1 += 2; sy2 += 2;
		su += 1; sv += 1;
		d1 += 2*BPP4; d2 += 2*BPP4;
	}

	/* convert the last 2x1 block: */
	if (dx & 1) {

		bu = butab[su[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		rv = rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + bu]  << 16)|
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + rv]  << 0);

		/* second line BGR0 */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + bu]  << 16)|
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + rv]  << 0);
	}
}

static void dblineI420toBGR32alpha (unsigned char *d1, unsigned char *d2, int dest_x,
									unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
									int src_x, int dx)
{
	register int y1, y2, ruv, guv, buv;
	register int i;

	/* convert first 2x1 block: */
	if (src_x & 1) {

		buv = butab[su[0]] + bvtab[sv[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		ruv = rutab[su[0]] + rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + buv] << 16)|
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + ruv] << 0);

		/* second line BGR0 */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + buv] << 16)|
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + ruv] << 0);

		sy1 += 1; sy2 += 1;
		su += 1; sv += 1;           /* shift luma !!! */
		d1 += BPP4; d2 += BPP4;
		dx --;
	}

	/* convert all integral 2x2 blocks: */
	for (i = 0; i < dx/2; i ++) {

		buv = butab[su[0]] + bvtab[sv[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		ruv = rutab[su[0]] + rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + buv] << 16)|
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + ruv] << 0);

		/* second line BGR0 */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + buv] << 16)|
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + ruv] << 0);

		y1 = ytab[sy1[1]];
		y2 = ytab[sy2[1]];

		/* first line BGR0 */
		*(unsigned int *)(d1+BPP4) =
			(CLIP8[y1 + buv] << 16)|
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + ruv] << 0);

		/* second line BGR0 */
		*(unsigned int *)(d2+BPP4) =
			(CLIP8[y2 + buv] << 16)|
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + ruv] << 0);

		/* next 2x2 block */
		sy1 += 2; sy2 += 2;
		su += 1; sv += 1;
		d1 += 2*BPP4; d2 += 2*BPP4;
	}

	/* convert last 2x1 block: */
	if (dx & 1) {

		buv = butab[su[0]] + bvtab[sv[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		ruv = rutab[su[0]] + rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + buv] << 16)|
			(CLIP8[y1 + guv] << 8) |
			(CLIP8[y1 + ruv] << 0);

		/* second line BGR0 */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + buv] << 16)|
			(CLIP8[y2 + guv] << 8) |
			(CLIP8[y2 + ruv] << 0);
	}
}

static void dblineI420toRGB24 (unsigned char *d1, unsigned char *d2, int dest_x,
							   unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
							   int src_x, int dx)
{
	/* check if we can use a fast 32-bit code: */
	if (LITTLE_ENDIAN && !((src_x ^ dest_x) & 1)) {

		/* aligned input/output on little-endian machine: */
		register int y11, y12, y13, y14, y21, y22, y23, y24;
		register int rv, rv2, guv, guv2, bu, bu2;
		register int i;

		/* convert first 2x1 block: */
		if (dest_x & 1) {

			bu = butab[su[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			rv = rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* first line BGR: */
			d1[0] = CLIP8[y11 + bu];
			d1[1] = CLIP8[y11 + guv];
			d1[2] = CLIP8[y11 + rv];

			/* second line BGR: */
			d2[0] = CLIP8[y21 + bu];
			d2[1] = CLIP8[y21 + guv];
			d2[2] = CLIP8[y21 + rv];

			sy1 += 1; sy2 += 1;
			su += 1; sv += 1;
			d1 += BPP3; d2 += BPP3;
			dest_x ++; dx --;
		}

		/* convert first 2x2 block: */
		if (dest_x & 2) {

			bu = butab[su[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			rv = rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* first line BGR: */
			d1[0] = CLIP8[y11 + bu];
			d1[1] = CLIP8[y11 + guv];
			d1[2] = CLIP8[y11 + rv];

			/* second line BGR: */
			d2[0] = CLIP8[y21 + bu];
			d2[1] = CLIP8[y21 + guv];
			d2[2] = CLIP8[y21 + rv];

			y12 = ytab[sy1[1]];
			y22 = ytab[sy2[1]];

			/* first line BGR: */
			d1[0+BPP3] = CLIP8[y12 + bu];
			d1[1+BPP3] = CLIP8[y12 + guv];
			d1[2+BPP3] = CLIP8[y12 + rv];

			/* second line BGR: */
			d2[0+BPP3] = CLIP8[y22 + bu];
			d2[1+BPP3] = CLIP8[y22 + guv];
			d2[2+BPP3] = CLIP8[y22 + rv];

			sy1 += 2; sy2 += 2;
			su += 1; sv += 1;
			d1 += 2*BPP3; d2 += 2*BPP3;
			dest_x += 2; dx -= 2;
		}

		/* convert all integral 2x4 blocks: */
		for (i = 0; i < dx/4; i ++) {

			bu = butab[su[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			rv = rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* first line BGRB */
			*(unsigned int *)(d1+0) =
				(CLIP8[y11 + bu])        |
				(CLIP8[y11 + guv] << 8)  |
				(CLIP8[y11 + rv]  << 16) |
				(CLIP8[y12 + bu]  << 24) ;

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			/* second line BGRB */
			*(unsigned int *)(d2+0) =
				(CLIP8[y21 + bu])        |
				(CLIP8[y21 + guv] << 8)  |
				(CLIP8[y21 + rv]  << 16) |
				(CLIP8[y22 + bu]  << 24) ;

			bu2 = butab[su[1]];
			guv2 = gutab[su[1]] + gvtab[sv[1]];
			y13 = ytab[sy1[2]];

			/* first line GRBG */
			*(unsigned int *)(d1+4) =
				(CLIP8[y12 + guv])        |
				(CLIP8[y12 + rv]   << 8)  |
				(CLIP8[y13 + bu2]  << 16) |
				(CLIP8[y13 + guv2] << 24) ;

			y23 = ytab[sy2[2]];

			/* second line GRBG */
			*(unsigned int *)(d2+4) =
				(CLIP8[y22 + guv])        |
				(CLIP8[y22 + rv]   << 8)  |
				(CLIP8[y23 + bu2]  << 16) |
				(CLIP8[y23 + guv2] << 24) ;

			y14 = ytab[sy1[3]];
			rv2 = rvtab[sv[1]];

			/* first line RBGR */
			*(unsigned int *)(d1+8) =
				(CLIP8[y13 + rv2])        |
				(CLIP8[y14 + bu2]  << 8)  |
				(CLIP8[y14 + guv2] << 16) |
				(CLIP8[y14 + rv2]  << 24) ;

			y24 = ytab[sy2[3]];

			/* second line RBGR */
			*(unsigned int *)(d2+8) =
				(CLIP8[y23 + rv2])        |
				(CLIP8[y24 + bu2]  << 8)  |
				(CLIP8[y24 + guv2] << 16) |
				(CLIP8[y24 + rv2]  << 24) ;

			/* next 4x2 block */
			sy1 += 4; sy2 += 4;
			su += 2; sv += 2;
			d1 += 4*BPP3; d2 += 4*BPP3;
		}

		/* convert last 2x2 block: */
		if (dx & 2) {

			bu = butab[su[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			rv = rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* first line BGR: */
			d1[0] = CLIP8[y11 + bu];
			d1[1] = CLIP8[y11 + guv];
			d1[2] = CLIP8[y11 + rv];

			/* second line BGR: */
			d2[0] = CLIP8[y21 + bu];
			d2[1] = CLIP8[y21 + guv];
			d2[2] = CLIP8[y21 + rv];

			y12 = ytab[sy1[1]];
			y22 = ytab[sy2[1]];

			/* first line BGR: */
			d1[0+BPP3] = CLIP8[y12 + bu];
			d1[1+BPP3] = CLIP8[y12 + guv];
			d1[2+BPP3] = CLIP8[y12 + rv];

			/* second line BGR: */
			d2[0+BPP3] = CLIP8[y22 + bu];
			d2[1+BPP3] = CLIP8[y22 + guv];
			d2[2+BPP3] = CLIP8[y22 + rv];

			sy1 += 2; sy2 += 2;
			su += 1; sv += 1;
			d1 += 2*BPP3; d2 += 2*BPP3;
			dx -= 2;
		}

		/* convert last 2x1 block: */
		if (dx & 1) {

			bu = butab[su[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			rv = rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* first line BGR: */
			d1[0] = CLIP8[y11 + bu];
			d1[1] = CLIP8[y11 + guv];
			d1[2] = CLIP8[y11 + rv];

			/* second line BGR: */
			d2[0] = CLIP8[y21 + bu];
			d2[1] = CLIP8[y21 + guv];
			d2[2] = CLIP8[y21 + rv];
		}

	} else {

		/* more generic implementation: */
		register int y11, y12, y21, y22;
		register int bu, rv, guv;
		register int i;

		/* convert first 2x1 block: */
		if (dest_x & 1) {

			bu = butab[su[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			rv = rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* first line BGR: */
			d1[0] = CLIP8[y11 + bu];
			d1[1] = CLIP8[y11 + guv];
			d1[2] = CLIP8[y11 + rv];

			/* second line BGR: */
			d2[0] = CLIP8[y21 + bu];
			d2[1] = CLIP8[y21 + guv];
			d2[2] = CLIP8[y21 + rv];

			sy1 += 1; sy2 += 1;
			su += 1; sv += 1;
			d1 += BPP3; d2 += BPP3;
			dest_x ++; dx --;
		}

		/* convert all integral 2x2 blocks: */
		for (i = 0; i < dx/2; i ++) {

			bu = butab[su[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			rv = rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* first line BGR,BGR: */
			d1[0] = CLIP8[y11 + bu];
			d1[1] = CLIP8[y11 + guv];
			d1[2] = CLIP8[y11 + rv];
			d1[3] = CLIP8[y12 + bu];
			d1[4] = CLIP8[y12 + guv];
			d1[5] = CLIP8[y12 + rv];

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			/* second line BGR,BGR: */
			d2[0] = CLIP8[y21 + bu];
			d2[1] = CLIP8[y21 + guv];
			d2[2] = CLIP8[y21 + rv];
			d2[3] = CLIP8[y22 + bu];
			d2[4] = CLIP8[y22 + guv];
			d2[5] = CLIP8[y22 + rv];

			/* next 2x2 block */
			sy1 += 2; sy2 += 2;
			su += 1; sv += 1;
			d1 += 2*BPP3; d2 += 2*BPP3;
		}

		/* convert last 2x1 block: */
		if (dx & 1) {

			bu = butab[su[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			rv = rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* first line BGR: */
			d1[0] = CLIP8[y11 + bu];
			d1[1] = CLIP8[y11 + guv];
			d1[2] = CLIP8[y11 + rv];

			/* second line BGR: */
			d2[0] = CLIP8[y21 + bu];
			d2[1] = CLIP8[y21 + guv];
			d2[2] = CLIP8[y21 + rv];
		}
	}
}

static void dblineI420toRGB24alpha (unsigned char *d1, unsigned char *d2, int dest_x,
									unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
									int src_x, int dx)
{
	/* check if we can use a fast 32-bit code: */
	if (LITTLE_ENDIAN && !((src_x ^ dest_x) & 1)) {

		/* aligned input/output on little-endian machine: */
		register int y11, y12, y13, y14, y21, y22, y23, y24;
		register int ruv, ruv2, guv, guv2, buv, buv2;
		register int i;

		/* convert first 2x1 block: */
		if (dest_x & 1) {

			buv = butab[su[0]] + bvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			ruv = rutab[su[0]] + rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* first line BGR */
			d1[0] = CLIP8[y11 + buv];
			d1[1] = CLIP8[y11 + guv];
			d1[2] = CLIP8[y11 + ruv];

			/* second line BGR */
			d2[0] = CLIP8[y21 + buv];
			d2[1] = CLIP8[y21 + guv];
			d2[2] = CLIP8[y21 + ruv];

			sy1 += 1; sy2 += 1;
			su += 1; sv += 1;
			d1 += BPP3; d2 += BPP3;
			dest_x ++; dx --;
		}

		/* convert first 2x2 block: */
		if (dest_x & 2) {

			buv = butab[su[0]] + bvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			ruv = rutab[su[0]] + rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* first line BGR */
			d1[0] = CLIP8[y11 + buv];
			d1[1] = CLIP8[y11 + guv];
			d1[2] = CLIP8[y11 + ruv];

			/* second line BGR */
			d2[0] = CLIP8[y21 + buv];
			d2[1] = CLIP8[y21 + guv];
			d2[2] = CLIP8[y21 + ruv];

			y12 = ytab[sy1[1]];
			y22 = ytab[sy2[1]];

			/* first line BGR */
			d1[0+BPP3] = CLIP8[y12 + buv];
			d1[1+BPP3] = CLIP8[y12 + guv];
			d1[2+BPP3] = CLIP8[y12 + ruv];

			/* second line BGR */
			d2[0+BPP3] = CLIP8[y22 + buv];
			d2[1+BPP3] = CLIP8[y22 + guv];
			d2[2+BPP3] = CLIP8[y22 + ruv];

			sy1 += 2; sy2 += 2;
			su += 1; sv += 1;
			d1 += 2*BPP3; d2 += 2*BPP3;
			dest_x += 2; dx -= 2;
		}

		/* convert all integral 2x4 blocks: */
		for (i = 0; i < dx/4; i ++) {

			buv = butab[su[0]] + bvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			ruv = rutab[su[0]] + rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* first line BGRB */
			*(unsigned int *)(d1+0) =
				(CLIP8[y11 + buv])       |
				(CLIP8[y11 + guv] << 8)  |
				(CLIP8[y11 + ruv] << 16) |
				(CLIP8[y12 + buv] << 24) ;

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			/* second line BGRB */
			*(unsigned int *)(d2+0) =
				(CLIP8[y21 + buv])       |
				(CLIP8[y21 + guv] << 8)  |
				(CLIP8[y21 + ruv] << 16) |
				(CLIP8[y22 + buv] << 24) ;

			buv2 = butab[su[1]] + bvtab[sv[1]];
			guv2 = gutab[su[1]] + gvtab[sv[1]];
			y13 = ytab[sy1[2]];

			/* first line GRBG */
			*(unsigned int *)(d1+4) =
				(CLIP8[y12 + guv])        |
				(CLIP8[y12 + ruv]  << 8)  |
				(CLIP8[y13 + buv2] << 16) |
				(CLIP8[y13 + guv2] << 24) ;

			y23 = ytab[sy2[2]];

			/* second line GRBG */
			*(unsigned int *)(d2+4) =
				(CLIP8[y22 + guv])        |
				(CLIP8[y22 + ruv]  << 8)  |
				(CLIP8[y23 + buv2] << 16) |
				(CLIP8[y23 + guv2] << 24) ;

			y14 = ytab[sy1[3]];
			ruv2 = rutab[su[1]]+rvtab[sv[1]];

			/* first line RBGR */
			*(unsigned int *)(d1+8) =
				(CLIP8[y13 + ruv2])       |
				(CLIP8[y14 + buv2] << 8)  |
				(CLIP8[y14 + guv2] << 16) |
				(CLIP8[y14 + ruv2] << 24) ;

			y24 = ytab[sy2[3]];

			/* second line RBGR */
			*(unsigned int *)(d2+8) =
				(CLIP8[y23 + ruv2])       |
				(CLIP8[y24 + buv2] << 8)  |
				(CLIP8[y24 + guv2] << 16) |
				(CLIP8[y24 + ruv2] << 24) ;

			/* next 4x2 block */
			sy1 += 4; sy2 += 4;
			su += 2; sv += 2;
			d1 += 4*BPP3; d2 += 4*BPP3;
		}

		/* convert last 2x2 block: */
		if (dx & 2) {

			buv = butab[su[0]] + bvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			ruv = rutab[su[0]] + rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* first line BGR */
			d1[0] = CLIP8[y11 + buv];
			d1[1] = CLIP8[y11 + guv];
			d1[2] = CLIP8[y11 + ruv];

			/* second line BGR */
			d2[0] = CLIP8[y21 + buv];
			d2[1] = CLIP8[y21 + guv];
			d2[2] = CLIP8[y21 + ruv];

			y12 = ytab[sy1[1]];
			y22 = ytab[sy2[1]];

			/* first line BGR */
			d1[0+BPP3] = CLIP8[y12 + buv];
			d1[1+BPP3] = CLIP8[y12 + guv];
			d1[2+BPP3] = CLIP8[y12 + ruv];

			/* second line BGR */
			d2[0+BPP3] = CLIP8[y22 + buv];
			d2[1+BPP3] = CLIP8[y22 + guv];
			d2[2+BPP3] = CLIP8[y22 + ruv];

			sy1 += 2; sy2 += 2;
			su += 1; sv += 1;
			d1 += 2*BPP3; d2 += 2*BPP3;
			dx -= 2;
		}

		/* convert last 2x1 block: */
		if (dx & 1) {

			buv = butab[su[0]] + bvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			ruv = rutab[su[0]] + rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* first line BGR */
			d1[0] = CLIP8[y11 + buv];
			d1[1] = CLIP8[y11 + guv];
			d1[2] = CLIP8[y11 + ruv];

			/* second line BGR */
			d2[0] = CLIP8[y21 + buv];
			d2[1] = CLIP8[y21 + guv];
			d2[2] = CLIP8[y21 + ruv];
		}

	} else {

		/* a more generic implentation */
		register int y11, y12, y21, y22;
		register int ruv, guv, buv;
		register int i;

		/* convert first 2x1 block: */
		if (dest_x & 1) {

			buv = butab[su[0]] + bvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			ruv = rutab[su[0]] + rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* first line BGR */
			d1[0] = CLIP8[y11 + buv];
			d1[1] = CLIP8[y11 + guv];
			d1[2] = CLIP8[y11 + ruv];

			/* second line BGR */
			d2[0] = CLIP8[y21 + buv];
			d2[1] = CLIP8[y21 + guv];
			d2[2] = CLIP8[y21 + ruv];

			sy1 += 1; sy2 += 1;
			su += 1; sv += 1;
			d1 += BPP3; d2 += BPP3;
			dest_x ++; dx --;
		}

		/* convert all integral 2x4 blocks: */
		for (i = 0; i < dx/2; i ++) {

			buv = butab[su[0]] + bvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			ruv = rutab[su[0]] + rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* first line BGR,BGR: */
			d1[0] = CLIP8[y11 + buv];
			d1[1] = CLIP8[y11 + guv];
			d1[2] = CLIP8[y11 + ruv];
			d1[3] = CLIP8[y12 + buv];
			d1[4] = CLIP8[y12 + guv];
			d1[5] = CLIP8[y12 + ruv];

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			/* second line BGR,BGR: */
			d2[0] = CLIP8[y21 + buv];
			d2[1] = CLIP8[y21 + guv];
			d2[2] = CLIP8[y21 + ruv];
			d2[3] = CLIP8[y22 + buv];
			d2[4] = CLIP8[y22 + guv];
			d2[5] = CLIP8[y22 + ruv];

			/* next 2x2 block */
			sy1 += 2; sy2 += 2;
			su += 1; sv += 1;
			d1 += 2*BPP3; d2 += 2*BPP3;
		}

		/* convert last 2x1 block: */
		if (dx & 1) {

			buv = butab[su[0]] + bvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			ruv = rutab[su[0]] + rvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* first line BGR */
			d1[0] = CLIP8[y11 + buv];
			d1[1] = CLIP8[y11 + guv];
			d1[2] = CLIP8[y11 + ruv];

			/* second line BGR */
			d2[0] = CLIP8[y21 + buv];
			d2[1] = CLIP8[y21 + guv];
			d2[2] = CLIP8[y21 + ruv];
		}
	}
}

static void dblineI420toRGB565 (unsigned char *d1, unsigned char *d2, int dest_x,
								unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
								int src_x, int dx)
{
	/* check if we have misaligned input/output: */
	if ((src_x ^ dest_x) & 1) {

		; /* not implemented yet */

	} else {

		/* aligned input/output: */
		register int y11, y12, y21, y22;
		register int rv, guv, bu;
		register int i;

		/* convert first 2x1 block: */
		if (dest_x & 1) {

			rv  = rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			bu  = butab[su[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* output 2 bytes at a time */
			*(unsigned short *)(d1+0) =
				(CLIP5[y11 + bu  + DITH5L] << 0)  |
				(CLIP6[y11 + guv + DITH6L] << 5)  |
				(CLIP5[y11 + rv  + DITH5L] << 11) ;

			*(unsigned short *)(d2+0) =
				(CLIP5[y21 + bu  + DITH5H] << 0)  |
				(CLIP6[y21 + guv + DITH6H] << 5)  |
				(CLIP5[y21 + rv  + DITH5H] << 11) ;

			sy1 += 1; sy2 += 1;
			su += 1; sv += 1;
			d1 += BPP2; d2 += BPP2;
			dest_x ++; dx --;
		}

		/* convert first 2x2 block: */
		if (dest_x & 2) {

			rv  = rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			bu  = butab[su[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* output 4 bytes at a time */
			*(unsigned int *)(d1+0) =
				(CLIP5[y11 + bu  + DITH5L] << 0)  |
				(CLIP6[y11 + guv + DITH6L] << 5)  |
				(CLIP5[y11 + rv  + DITH5L] << 11) |
				(CLIP5[y12 + bu  + DITH5H] << 16) |
				(CLIP6[y12 + guv + DITH6H] << 21) |
				(CLIP5[y12 + rv  + DITH5H] << 27) ;

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			*(unsigned int *)(d2+0) =
				(CLIP5[y21 + bu  + DITH5H] << 0)  |
				(CLIP6[y21 + guv + DITH6H] << 5)  |
				(CLIP5[y21 + rv  + DITH5H] << 11) |
				(CLIP5[y22 + bu  + DITH5L] << 16) |
				(CLIP6[y22 + guv + DITH6L] << 21) |
				(CLIP5[y22 + rv  + DITH5L] << 27) ;

			sy1 += 2; sy2 += 2;
			su += 1; sv += 1;
			d1 += 2*BPP2; d2 += 2*BPP2;
			dest_x += 2; dx -= 2;
		}

		/* convert all integral 2x4 blocks: */
		for (i = 0; i < dx/4; i ++) {

			/* first 2x2 block */
			rv = rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			bu = butab[su[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* output 4 bytes at a time */
			*(unsigned int *)(d1+0) =
				(CLIP5[y11 + bu  + DITH5L] << 0)  |
				(CLIP6[y11 + guv + DITH6L] << 5)  |
				(CLIP5[y11 + rv  + DITH5L] << 11) |
				(CLIP5[y12 + bu  + DITH5H] << 16) |
				(CLIP6[y12 + guv + DITH6H] << 21) |
				(CLIP5[y12 + rv  + DITH5H] << 27) ;

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			*(unsigned int *)(d2+0) =
				(CLIP5[y21 + bu  + DITH5H] << 0)  |
				(CLIP6[y21 + guv + DITH6H] << 5)  |
				(CLIP5[y21 + rv  + DITH5H] << 11) |
				(CLIP5[y22 + bu  + DITH5L] << 16) |
				(CLIP6[y22 + guv + DITH6L] << 21) |
				(CLIP5[y22 + rv  + DITH5L] << 27) ;

			/* second 2x2 block */
			rv  = rvtab[sv[1]];
			guv = gutab[su[1]] + gvtab[sv[1]];
			bu  = butab[su[1]];
			y11 = ytab[sy1[2]];
			y12 = ytab[sy1[3]];

			*(unsigned int *)(d1+2*BPP2) =
				(CLIP5[y11 + bu  + DITH5L] << 0)  |
				(CLIP6[y11 + guv + DITH6L] << 5)  |
				(CLIP5[y11 + rv  + DITH5L] << 11) |
				(CLIP5[y12 + bu  + DITH5H] << 16) |
				(CLIP6[y12 + guv + DITH6H] << 21) |
				(CLIP5[y12 + rv  + DITH5H] << 27) ;

			y21 = ytab[sy2[2]];
			y22 = ytab[sy2[3]];

			*(unsigned int *)(d2+2*BPP2) =
				(CLIP5[y21 + bu  + DITH5H] << 0)  |
				(CLIP6[y21 + guv + DITH6H] << 5)  |
				(CLIP5[y21 + rv  + DITH5H] << 11) |
				(CLIP5[y22 + bu  + DITH5L] << 16) |
				(CLIP6[y22 + guv + DITH6L] << 21) |
				(CLIP5[y22 + rv  + DITH5L] << 27) ;

			/* next 4x2 block */
			sy1 += 4; sy2 += 4;
			su += 2; sv += 2;
			d1 += 4*BPP2; d2 += 4*BPP2;
		}

		/* convert last 2x2 block: */
		if (dx & 2) {

			rv = rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			bu = butab[su[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* output 4 bytes at a time */
			*(unsigned int *)(d1+0) =
				(CLIP5[y11 + bu  + DITH5L] << 0)  |
				(CLIP6[y11 + guv + DITH6L] << 5)  |
				(CLIP5[y11 + rv  + DITH5L] << 11) |
				(CLIP5[y12 + bu  + DITH5H] << 16) |
				(CLIP6[y12 + guv + DITH6H] << 21) |
				(CLIP5[y12 + rv  + DITH5H] << 27) ;

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			*(unsigned int *)(d2+0) =
				(CLIP5[y21 + bu  + DITH5H] << 0)  |
				(CLIP6[y21 + guv + DITH6H] << 5)  |
				(CLIP5[y21 + rv  + DITH5H] << 11) |
				(CLIP5[y22 + bu  + DITH5L] << 16) |
				(CLIP6[y22 + guv + DITH6L] << 21) |
				(CLIP5[y22 + rv  + DITH5L] << 27) ;

			sy1 += 2; sy2 += 2;
			su += 1; sv += 1;
			d1 += 2*BPP2; d2 += 2*BPP2;
			dx -= 2;
		}

		/* convert last 2x1 block: */
		if (dx & 1) {

			rv  = rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			bu  = butab[su[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* output 2 bytes at a time */
			*(unsigned short *)(d1+0) =
				(CLIP5[y11 + bu  + DITH5L] << 0)  |
				(CLIP6[y11 + guv + DITH6L] << 5)  |
				(CLIP5[y11 + rv  + DITH5L] << 11) ;

			*(unsigned short *)(d2+0) =
				(CLIP5[y21 + bu  + DITH5H] << 0)  |
				(CLIP6[y21 + guv + DITH6H] << 5)  |
				(CLIP5[y21 + rv  + DITH5H] << 11) ;
		}
	}
}

static void dblineI420toRGB565alpha (unsigned char *d1, unsigned char *d2, int dest_x,
									 unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
									 int src_x, int dx)
{
	/* check if we have misaligned input/output: */
	if ((src_x ^ dest_x) & 1) {

		; /* not implemented yet */

	} else {

		/* aligned input/output: */
		register int y11, y12, y21, y22;
		register int ruv, guv, buv;
		register int i;

		/* convert first 2x1 block: */
		if (dest_x & 1) {

			ruv = rutab[su[0]] + rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			buv = butab[su[0]] + bvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* output 2 bytes at a time */
			*(unsigned short *)(d1+0) =
				(CLIP5[y11 + buv + DITH5L] << 0)  |
				(CLIP6[y11 + guv + DITH6L] << 5)  |
				(CLIP5[y11 + ruv + DITH5L] << 11) ;

			*(unsigned short *)(d2+0) =
				(CLIP5[y21 + buv + DITH5H] << 0)  |
				(CLIP6[y21 + guv + DITH6H] << 5)  |
				(CLIP5[y21 + ruv + DITH5H] << 11) ;

			sy1 += 1; sy2 += 1;
			su += 1; sv += 1;
			d1 += BPP2; d2 += BPP2;
			dest_x ++; dx --;
		}

		/* convert first 2x2 block: */
		if (dest_x & 2) {

			ruv = rutab[su[0]] + rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			buv = butab[su[0]] + bvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* output 4 bytes at a time */
			*(unsigned int *)(d1+0) =
				(CLIP5[y11 + buv + DITH5L] << 0)  |
				(CLIP6[y11 + guv + DITH6L] << 5)  |
				(CLIP5[y11 + ruv + DITH5L] << 11) |
				(CLIP5[y12 + buv + DITH5H] << 16) |
				(CLIP6[y12 + guv + DITH6H] << 21) |
				(CLIP5[y12 + ruv + DITH5H] << 27) ;

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			*(unsigned int *)(d2+0) =
				(CLIP5[y21 + buv + DITH5H] << 0)  |
				(CLIP6[y21 + guv + DITH6H] << 5)  |
				(CLIP5[y21 + ruv + DITH5H] << 11) |
				(CLIP5[y22 + buv + DITH5L] << 16) |
				(CLIP6[y22 + guv + DITH6L] << 21) |
				(CLIP5[y22 + ruv + DITH5L] << 27) ;

			sy1 += 2; sy2 += 2;
			su += 1; sv += 1;
			d1 += 2*BPP2; d2 += 2*BPP2;
			dest_x += 2; dx -= 2;
		}

		/* convert all integral 2x4 blocks: */
		for (i = 0; i < dx/4; i ++) {

			/* first 2x2 block */
			ruv = rutab[su[0]] + rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			buv = butab[su[0]] + bvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* output 4 bytes at a time */
			*(unsigned int *)(d1+0) =
				(CLIP5[y11 + buv + DITH5L] << 0)  |
				(CLIP6[y11 + guv + DITH6L] << 5)  |
				(CLIP5[y11 + ruv + DITH5L] << 11) |
				(CLIP5[y12 + buv + DITH5H] << 16) |
				(CLIP6[y12 + guv + DITH6H] << 21) |
				(CLIP5[y12 + ruv + DITH5H] << 27) ;

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			*(unsigned int *)(d2+0) =
				(CLIP5[y21 + buv + DITH5H] << 0)  |
				(CLIP6[y21 + guv + DITH6H] << 5)  |
				(CLIP5[y21 + ruv + DITH5H] << 11) |
				(CLIP5[y22 + buv + DITH5L] << 16) |
				(CLIP6[y22 + guv + DITH6L] << 21) |
				(CLIP5[y22 + ruv + DITH5L] << 27) ;

			/* second 2x2 block */
			ruv = rutab[su[1]] + rvtab[sv[1]];
			guv = gutab[su[1]] + gvtab[sv[1]];
			buv = butab[su[1]] + bvtab[sv[1]];
			y11 = ytab[sy1[2]];
			y12 = ytab[sy1[3]];

			*(unsigned int *)(d1+2*BPP2) =
				(CLIP5[y11 + buv + DITH5L] << 0)  |
				(CLIP6[y11 + guv + DITH6L] << 5)  |
				(CLIP5[y11 + ruv + DITH5L] << 11) |
				(CLIP5[y12 + buv + DITH5H] << 16) |
				(CLIP6[y12 + guv + DITH6H] << 21) |
				(CLIP5[y12 + ruv + DITH5H] << 27) ;

			y21 = ytab[sy2[2]];
			y22 = ytab[sy2[3]];

			*(unsigned int *)(d2+2*BPP2) =
				(CLIP5[y21 + buv + DITH5H] << 0)  |
				(CLIP6[y21 + guv + DITH6H] << 5)  |
				(CLIP5[y21 + ruv + DITH5H] << 11) |
				(CLIP5[y22 + buv + DITH5L] << 16) |
				(CLIP6[y22 + guv + DITH6L] << 21) |
				(CLIP5[y22 + ruv + DITH5L] << 27) ;

			/* next 4x2 block */
			sy1 += 4; sy2 += 4;
			su += 2; sv += 2;
			d1 += 4*BPP2; d2 += 4*BPP2;
		}

		/* convert last 2x2 block: */
		if (dx & 2) {

			ruv = rutab[su[0]] + rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			buv = butab[su[0]] + bvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* output 4 bytes at a time */
			*(unsigned int *)(d1+0) =
				(CLIP5[y11 + buv + DITH5L] << 0)  |
				(CLIP6[y11 + guv + DITH6L] << 5)  |
				(CLIP5[y11 + ruv + DITH5L] << 11) |
				(CLIP5[y12 + buv + DITH5H] << 16) |
				(CLIP6[y12 + guv + DITH6H] << 21) |
				(CLIP5[y12 + ruv + DITH5H] << 27) ;

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			*(unsigned int *)(d2+0) =
				(CLIP5[y21 + buv + DITH5H] << 0)  |
				(CLIP6[y21 + guv + DITH6H] << 5)  |
				(CLIP5[y21 + ruv + DITH5H] << 11) |
				(CLIP5[y22 + buv + DITH5L] << 16) |
				(CLIP6[y22 + guv + DITH6L] << 21) |
				(CLIP5[y22 + ruv + DITH5L] << 27) ;

			sy1 += 2; sy2 += 2;
			su += 1; sv += 1;
			d1 += 2*BPP2; d2 += 2*BPP2;
			dx -= 2;
		}

		/* convert last 2x1 block: */
		if (dx & 1) {

			ruv = rutab[su[0]] + rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			buv = butab[su[0]] + bvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* output 2 bytes at a time */
			*(unsigned short *)(d1+0) =
				(CLIP5[y11 + buv + DITH5L] << 0)  |
				(CLIP6[y11 + guv + DITH6L] << 5)  |
				(CLIP5[y11 + ruv + DITH5L] << 11) ;

			*(unsigned short *)(d2+0) =
				(CLIP5[y21 + buv + DITH5H] << 0)  |
				(CLIP6[y21 + guv + DITH6H] << 5)  |
				(CLIP5[y21 + ruv + DITH5H] << 11) ;
		}
	}
}

static void dblineI420toRGB555 (unsigned char *d1, unsigned char *d2, int dest_x,
								unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
								int src_x, int dx)
{
	/* check if we have misaligned input/output: */
	if ((src_x ^ dest_x) & 1) {

		; /* not implemented yet */

	} else {

		/* aligned input/output: */
		register int y11, y12, y21, y22;
		register int rv, guv, bu;
		register int i;

		/* convert first 2x1 block: */
		if (dest_x & 1) {

			rv  = rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			bu  = butab[su[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* output 2 bytes at a time */
			*(unsigned short *)(d1+0) =
				(CLIP5[y11 + bu  + DITH5L] << 0)  |
				(CLIP5[y11 + guv + DITH5L] << 5)  |
				(CLIP5[y11 + rv  + DITH5L] << 10) ;

			*(unsigned short *)(d2+0) =
				(CLIP5[y21 + bu  + DITH5H] << 0)  |
				(CLIP5[y21 + guv + DITH5H] << 5)  |
				(CLIP5[y21 + rv  + DITH5H] << 10) ;

			sy1 += 1; sy2 += 1;
			su += 1; sv += 1;
			d1 += BPP2; d2 += BPP2;
			dest_x ++; dx --;
		}

		/* convert first 2x2 block: */
		if (dest_x & 2) {

			rv  = rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			bu  = butab[su[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* output 4 bytes at a time */
			*(unsigned int *)(d1+0) =
				(CLIP5[y11 + bu  + DITH5L] << 0)  |
				(CLIP5[y11 + guv + DITH5L] << 5)  |
				(CLIP5[y11 + rv  + DITH5L] << 10) |
				(CLIP5[y12 + bu  + DITH5H] << 16) |
				(CLIP5[y12 + guv + DITH5H] << 21) |
				(CLIP5[y12 + rv  + DITH5H] << 26) ;

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			*(unsigned int *)(d2+0) =
				(CLIP5[y21 + bu  + DITH5H] << 0)  |
				(CLIP5[y21 + guv + DITH5H] << 5)  |
				(CLIP5[y21 + rv  + DITH5H] << 10) |
				(CLIP5[y22 + bu  + DITH5L] << 16) |
				(CLIP5[y22 + guv + DITH5L] << 21) |
				(CLIP5[y22 + rv  + DITH5L] << 26) ;

			sy1 += 2; sy2 += 2;
			su += 1; sv += 1;
			d1 += 2*BPP2; d2 += 2*BPP2;
			dest_x += 2; dx -= 2;
		}

		/* convert all integral 2x4 blocks: */
		for (i = 0; i < dx/4; i ++) {

			/* first 2x2 block */
			rv = rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			bu = butab[su[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* output 4 bytes at a time */
			*(unsigned int *)(d1+0) =
				(CLIP5[y11 + bu  + DITH5L] << 0)  |
				(CLIP5[y11 + guv + DITH5L] << 5)  |
				(CLIP5[y11 + rv  + DITH5L] << 10) |
				(CLIP5[y12 + bu  + DITH5H] << 16) |
				(CLIP5[y12 + guv + DITH5H] << 21) |
				(CLIP5[y12 + rv  + DITH5H] << 26) ;

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			*(unsigned int *)(d2+0) =
				(CLIP5[y21 + bu  + DITH5H] << 0)  |
				(CLIP5[y21 + guv + DITH5H] << 5)  |
				(CLIP5[y21 + rv  + DITH5H] << 10) |
				(CLIP5[y22 + bu  + DITH5L] << 16) |
				(CLIP5[y22 + guv + DITH5L] << 21) |
				(CLIP5[y22 + rv  + DITH5L] << 26) ;

			/* second 2x2 block */
			rv  = rvtab[sv[1]];
			guv = gutab[su[1]] + gvtab[sv[1]];
			bu  = butab[su[1]];
			y11 = ytab[sy1[2]];
			y12 = ytab[sy1[3]];

			*(unsigned int *)(d1+2*BPP2) =
				(CLIP5[y11 + bu  + DITH5L] << 0)  |
				(CLIP5[y11 + guv + DITH5L] << 5)  |
				(CLIP5[y11 + rv  + DITH5L] << 10) |
				(CLIP5[y12 + bu  + DITH5H] << 16) |
				(CLIP5[y12 + guv + DITH5H] << 21) |
				(CLIP5[y12 + rv  + DITH5H] << 26) ;

			y21 = ytab[sy2[2]];
			y22 = ytab[sy2[3]];

			*(unsigned int *)(d2+2*BPP2) =
				(CLIP5[y21 + bu  + DITH5H] << 0)  |
				(CLIP5[y21 + guv + DITH5H] << 5)  |
				(CLIP5[y21 + rv  + DITH5H] << 10) |
				(CLIP5[y22 + bu  + DITH5L] << 16) |
				(CLIP5[y22 + guv + DITH5L] << 21) |
				(CLIP5[y22 + rv  + DITH5L] << 26) ;

			/* next 4x2 block */
			sy1 += 4; sy2 += 4;
			su += 2; sv += 2;
			d1 += 4*BPP2; d2 += 4*BPP2;
		}

		/* convert last 2x2 block: */
		if (dx & 2) {

			rv = rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			bu = butab[su[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* output 4 bytes at a time */
			*(unsigned int *)(d1+0) =
				(CLIP5[y11 + bu  + DITH5L] << 0)  |
				(CLIP5[y11 + guv + DITH5L] << 5)  |
				(CLIP5[y11 + rv  + DITH5L] << 10) |
				(CLIP5[y12 + bu  + DITH5H] << 16) |
				(CLIP5[y12 + guv + DITH5H] << 21) |
				(CLIP5[y12 + rv  + DITH5H] << 26) ;

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			*(unsigned int *)(d2+0) =
				(CLIP5[y21 + bu  + DITH5H] << 0)  |
				(CLIP5[y21 + guv + DITH5H] << 5)  |
				(CLIP5[y21 + rv  + DITH5H] << 10) |
				(CLIP5[y22 + bu  + DITH5L] << 16) |
				(CLIP5[y22 + guv + DITH5L] << 21) |
				(CLIP5[y22 + rv  + DITH5L] << 26) ;

			sy1 += 2; sy2 += 2;
			su += 1; sv += 1;
			d1 += 2*BPP2; d2 += 2*BPP2;
			dx -= 2;
		}

		/* convert last 2x1 block: */
		if (dx & 1) {

			rv  = rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			bu  = butab[su[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* output 2 bytes at a time */
			*(unsigned short *)(d1+0) =
				(CLIP5[y11 + bu  + DITH5L] << 0)  |
				(CLIP5[y11 + guv + DITH5L] << 5)  |
				(CLIP5[y11 + rv  + DITH5L] << 10) ;

			*(unsigned short *)(d2+0) =
				(CLIP5[y21 + bu  + DITH5H] << 0)  |
				(CLIP5[y21 + guv + DITH5H] << 5)  |
				(CLIP5[y21 + rv  + DITH5H] << 10) ;
		}
	}
}

static void dblineI420toRGB555alpha (unsigned char *d1, unsigned char *d2, int dest_x,
									 unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
									 int src_x, int dx)
{
	/* check if we have misaligned input/output: */
	if ((src_x ^ dest_x) & 1) {

		; /* not implemented yet */

	} else {

		/* aligned input/output: */
		register int y11, y12, y21, y22;
		register int ruv, guv, buv;
		register int i;

		/* convert first 2x1 block: */
		if (dest_x & 1) {

			ruv = rutab[su[0]] + rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			buv = butab[su[0]] + bvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* output 2 bytes at a time */
			*(unsigned short *)(d1+0) =
				(CLIP5[y11 + buv + DITH5L] << 0)  |
				(CLIP5[y11 + guv + DITH5L] << 5)  |
				(CLIP5[y11 + ruv + DITH5L] << 10) ;

			*(unsigned short *)(d2+0) =
				(CLIP5[y21 + buv + DITH5H] << 0)  |
				(CLIP5[y21 + guv + DITH5H] << 5)  |
				(CLIP5[y21 + ruv + DITH5H] << 10) ;

			sy1 += 1; sy2 += 1;
			su += 1; sv += 1;
			d1 += BPP2; d2 += BPP2;
			dest_x ++; dx --;
		}

		/* convert first 2x2 block: */
		if (dest_x & 2) {

			ruv = rutab[su[0]] + rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			buv = butab[su[0]] + bvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* output 4 bytes at a time */
			*(unsigned int *)(d1+0) =
				(CLIP5[y11 + buv + DITH5L] << 0)  |
				(CLIP5[y11 + guv + DITH5L] << 5)  |
				(CLIP5[y11 + ruv + DITH5L] << 10) |
				(CLIP5[y12 + buv + DITH5H] << 16) |
				(CLIP5[y12 + guv + DITH5H] << 21) |
				(CLIP5[y12 + ruv + DITH5H] << 26) ;

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			*(unsigned int *)(d2+0) =
				(CLIP5[y21 + buv + DITH5H] << 0)  |
				(CLIP5[y21 + guv + DITH5H] << 5)  |
				(CLIP5[y21 + ruv + DITH5H] << 10) |
				(CLIP5[y22 + buv + DITH5L] << 16) |
				(CLIP5[y22 + guv + DITH5L] << 21) |
				(CLIP5[y22 + ruv + DITH5L] << 26) ;

			sy1 += 2; sy2 += 2;
			su += 1; sv += 1;
			d1 += 2*BPP2; d2 += 2*BPP2;
			dest_x += 2; dx -= 2;
		}

		/* convert all integral 2x4 blocks: */
		for (i = 0; i < dx/4; i ++) {

			/* first 2x2 block */
			ruv = rutab[su[0]] + rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			buv = butab[su[0]] + bvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* output 4 bytes at a time */
			*(unsigned int *)(d1+0) =
				(CLIP5[y11 + buv + DITH5L] << 0)  |
				(CLIP5[y11 + guv + DITH5L] << 5)  |
				(CLIP5[y11 + ruv + DITH5L] << 10) |
				(CLIP5[y12 + buv + DITH5H] << 16) |
				(CLIP5[y12 + guv + DITH5H] << 21) |
				(CLIP5[y12 + ruv + DITH5H] << 26) ;

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			*(unsigned int *)(d2+0) =
				(CLIP5[y21 + buv + DITH5H] << 0)  |
				(CLIP5[y21 + guv + DITH5H] << 5)  |
				(CLIP5[y21 + ruv + DITH5H] << 10) |
				(CLIP5[y22 + buv + DITH5L] << 16) |
				(CLIP5[y22 + guv + DITH5L] << 21) |
				(CLIP5[y22 + ruv + DITH5L] << 26) ;

			/* second 2x2 block */
			ruv = rutab[su[1]] + rvtab[sv[1]];
			guv = gutab[su[1]] + gvtab[sv[1]];
			buv = butab[su[1]] + bvtab[sv[1]];
			y11 = ytab[sy1[2]];
			y12 = ytab[sy1[3]];

			*(unsigned int *)(d1+2*BPP2) =
				(CLIP5[y11 + buv + DITH5L] << 0)  |
				(CLIP5[y11 + guv + DITH5L] << 5)  |
				(CLIP5[y11 + ruv + DITH5L] << 10) |
				(CLIP5[y12 + buv + DITH5H] << 16) |
				(CLIP5[y12 + guv + DITH5H] << 21) |
				(CLIP5[y12 + ruv + DITH5H] << 26) ;

			y21 = ytab[sy2[2]];
			y22 = ytab[sy2[3]];

			*(unsigned int *)(d2+2*BPP2) =
				(CLIP5[y21 + buv + DITH5H] << 0)  |
				(CLIP5[y21 + guv + DITH5H] << 5)  |
				(CLIP5[y21 + ruv + DITH5H] << 10) |
				(CLIP5[y22 + buv + DITH5L] << 16) |
				(CLIP5[y22 + guv + DITH5L] << 21) |
				(CLIP5[y22 + ruv + DITH5L] << 26) ;

			/* next 4x2 block */
			sy1 += 4; sy2 += 4;
			su += 2; sv += 2;
			d1 += 4*BPP2; d2 += 4*BPP2;
		}

		/* convert last 2x2 block: */
		if (dx & 2) {

			ruv = rutab[su[0]] + rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			buv = butab[su[0]] + bvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y12 = ytab[sy1[1]];

			/* output 4 bytes at a time */
			*(unsigned int *)(d1+0) =
				(CLIP5[y11 + buv + DITH5L] << 0)  |
				(CLIP5[y11 + guv + DITH5L] << 5)  |
				(CLIP5[y11 + ruv + DITH5L] << 10) |
				(CLIP5[y12 + buv + DITH5H] << 16) |
				(CLIP5[y12 + guv + DITH5H] << 21) |
				(CLIP5[y12 + ruv + DITH5H] << 26) ;

			y21 = ytab[sy2[0]];
			y22 = ytab[sy2[1]];

			*(unsigned int *)(d2+0) =
				(CLIP5[y21 + buv + DITH5H] << 0)  |
				(CLIP5[y21 + guv + DITH5H] << 5)  |
				(CLIP5[y21 + ruv + DITH5H] << 10) |
				(CLIP5[y22 + buv + DITH5L] << 16) |
				(CLIP5[y22 + guv + DITH5L] << 21) |
				(CLIP5[y22 + ruv + DITH5L] << 26) ;

			sy1 += 2; sy2 += 2;
			su += 1; sv += 1;
			d1 += 2*BPP2; d2 += 2*BPP2;
			dx -= 2;
		}

		/* convert last 2x1 block: */
		if (dx & 1) {

			ruv = rutab[su[0]] + rvtab[sv[0]];
			guv = gutab[su[0]] + gvtab[sv[0]];
			buv = butab[su[0]] + bvtab[sv[0]];
			y11 = ytab[sy1[0]];
			y21 = ytab[sy2[0]];

			/* output 2 bytes at a time */
			*(unsigned short *)(d1+0) =
				(CLIP5[y11 + buv + DITH5L] << 0)  |
				(CLIP5[y11 + guv + DITH5L] << 5)  |
				(CLIP5[y11 + ruv + DITH5L] << 10) ;

			*(unsigned short *)(d2+0) =
				(CLIP5[y21 + buv + DITH5H] << 0)  |
				(CLIP5[y21 + guv + DITH5H] << 5)  |
				(CLIP5[y21 + ruv + DITH5H] << 10) ;
		}
	}
}

static void dblineI420toRGB8 (unsigned char *d1, unsigned char *d2, int dest_x,
							  unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
							  int src_x, int dx)
{
	register int y1, y2, rv, guv, bu;
	register int i;

	/* convert first 2x1 block: */
	if (src_x & 1) {

		bu = butab[su[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		rv = rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(d1+0) = pmap[
			(CLIP4[y1 + bu  + DITH4H] << 0) |
				(CLIP4[y1 + guv + DITH4H] << 4) |
				(CLIP4[y1 + rv  + DITH4H] << 8)];

			/* second line BGR0 */
			*(d2+0) = pmap[
				(CLIP4[y2 + bu  + DITH4L] << 0) |
					(CLIP4[y2 + guv + DITH4L] << 4) |
					(CLIP4[y2 + rv  + DITH4L] << 8)];

				sy1 += 1; sy2 += 1;
				su += 1; sv += 1;           /* shift luma !!! */
				d1 += BPP1; d2 += BPP1;
				dx --;
	}

	/* convert all integral 2x2 blocks: */
	for (i = 0; i < dx/2; i ++) {

		bu = butab[su[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		rv = rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(d1+0) = pmap[
			(CLIP4[y1 + bu  + DITH4L] << 0) |
				(CLIP4[y1 + guv + DITH4L] << 4) |
				(CLIP4[y1 + rv  + DITH4L] << 8)];

			/* second line BGR0 */
			*(d2+0) = pmap[
				(CLIP4[y2 + bu  + DITH4H] << 0) |
					(CLIP4[y2 + guv + DITH4H] << 4) |
					(CLIP4[y2 + rv  + DITH4H] << 8)];

				/* 2nd column: */
				y1 = ytab[sy1[1]];
				y2 = ytab[sy2[1]];

				/* first line BGR0 */
				*(d1+BPP1) = pmap[
					(CLIP4[y1 + bu  + DITH4H] << 0) |
						(CLIP4[y1 + guv + DITH4H] << 4) |
						(CLIP4[y1 + rv  + DITH4H] << 8)];

					/* second line BGR0 */
					*(d2+BPP1) = pmap[
						(CLIP4[y2 + bu  + DITH4L] << 0) |
							(CLIP4[y2 + guv + DITH4L] << 4) |
							(CLIP4[y2 + rv  + DITH4L] << 8)];

						/* next 2x2 block */
						sy1 += 2; sy2 += 2;
						su += 1; sv += 1;
						d1 += 2*BPP1; d2 += 2*BPP1;
	}

	/* convert the last 2x1 block: */
	if (dx & 1) {

		bu = butab[su[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		rv = rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(d1+0) = pmap[
			(CLIP4[y1 + bu  + DITH4L] << 0) |
				(CLIP4[y1 + guv + DITH4L] << 4) |
				(CLIP4[y1 + rv  + DITH4L] << 8)];

			/* second line BGR0 */
			*(d2+0) = pmap[
				(CLIP4[y2 + bu  + DITH4H] << 0) |
					(CLIP4[y2 + guv + DITH4H] << 4) |
					(CLIP4[y2 + rv  + DITH4H] << 8)];
	}
}

static void dblineI420toRGB8alpha (unsigned char *d1, unsigned char *d2, int dest_x,
								   unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
								   int src_x, int dx)
{
	register int y1, y2, ruv, guv, buv;
	register int i;

	/* convert first 2x1 block: */
	if (src_x & 1) {

		buv = butab[su[0]] + bvtab[sv[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		ruv = rutab[su[0]] + rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(d1+0) = pmap[
			(CLIP4[y1 + buv + DITH4H] << 0) |
				(CLIP4[y1 + guv + DITH4H] << 4) |
				(CLIP4[y1 + ruv + DITH4H] << 8)];

			/* second line BGR0 */
			*(d2+0) = pmap[
				(CLIP4[y2 + buv + DITH4L] << 0) |
					(CLIP4[y2 + guv + DITH4L] << 4) |
					(CLIP4[y2 + ruv + DITH4L] << 8)];

				sy1 += 1; sy2 += 1;
				su += 1; sv += 1;           /* shift luma !!! */
				d1 += BPP1; d2 += BPP1;
				dx --;
	}

	/* convert all integral 2x2 blocks: */
	for (i = 0; i < dx/2; i ++) {

		buv = butab[su[0]] + bvtab[sv[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		ruv = rutab[su[0]] + rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(d1+0) = pmap[
			(CLIP4[y1 + buv + DITH4L] << 0) |
				(CLIP4[y1 + guv + DITH4L] << 4) |
				(CLIP4[y1 + ruv + DITH4L] << 8)];

			/* second line BGR0 */
			*(d2+0) = pmap[
				(CLIP4[y2 + buv + DITH4H] << 0) |
					(CLIP4[y2 + guv + DITH4H] << 4) |
					(CLIP4[y2 + ruv + DITH4H] << 8)];

				y1 = ytab[sy1[1]];
				y2 = ytab[sy2[1]];

				/* first line BGR0 */
				*(d1+BPP1) = pmap[
					(CLIP4[y1 + buv + DITH4H] << 0) |
						(CLIP4[y1 + guv + DITH4H] << 4) |
						(CLIP4[y1 + ruv + DITH4H] << 8)];

					/* second line BGR0 */
					*(d2+BPP1) = pmap[
						(CLIP4[y2 + buv + DITH4L] << 0) |
							(CLIP4[y2 + guv + DITH4L] << 4) |
							(CLIP4[y2 + ruv + DITH4L] << 8)];

						/* next 2x2 block */
						sy1 += 2; sy2 += 2;
						su += 1; sv += 1;
						d1 += 2*BPP1; d2 += 2*BPP1;
	}

	/* convert last 2x1 block: */
	if (dx & 1) {

		buv = butab[su[0]] + bvtab[sv[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		ruv = rutab[su[0]] + rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line BGR0 */
		*(d1+0) = pmap[
			(CLIP4[y1 + buv + DITH4L] << 0) |
				(CLIP4[y1 + guv + DITH4L] << 4) |
				(CLIP4[y1 + ruv + DITH4L] << 8)];

			/* second line BGR0 */
			*(d2+0) = pmap[
				(CLIP4[y2 + buv + DITH4H] << 0) |
					(CLIP4[y2 + guv + DITH4H] << 4) |
					(CLIP4[y2 + ruv + DITH4H] << 8)];
	}
}

/*
* Convert two YUV lines into RGB linebufs.
* Produces two RGB lines per call.
* Output in padded RGB format, needed for SIMD interpolation.
*/
static void dblineI420toXRGB (unsigned char *d1, unsigned char *d2, int dest_x,
							  unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
							  int src_x, int dx)
{
	register int y1, y2, rv, guv, bu;
	register int i;

	/* convert first 2x1 block: */
	if (src_x & 1) {

		bu = butab[su[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		rv = rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line 00rrrrrr.rr000ggg.ggggg000.bbbbbbbb: */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + bu])        |
			(CLIP8[y1 + guv] << 11) |
			(CLIP8[y1 + rv]  << 22) ;

		/* second line 00rrrrrr.rr000ggg.ggggg000.bbbbbbbb: */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + bu])        |
			(CLIP8[y2 + guv] << 11) |
			(CLIP8[y2 + rv]  << 22) ;

		sy1 += 1; sy2 += 1;
		su += 1; sv += 1;
		d1 += BPP4; d2 += BPP4;
		dx --;
	}

	/* convert all integral 2x2 blocks: */
	for (i = 0; i < dx/2; i ++) {

		bu = butab[su[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		rv = rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line 00rrrrrr.rr000ggg.ggggg000.bbbbbbbb: */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + bu])        |
			(CLIP8[y1 + guv] << 11) |
			(CLIP8[y1 + rv]  << 22) ;

		/* second line 00rrrrrr.rr000ggg.ggggg000.bbbbbbbb: */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + bu])        |
			(CLIP8[y2 + guv] << 11) |
			(CLIP8[y2 + rv]  << 22) ;

		/* 2nd row: */
		y1 = ytab[sy1[1]];
		y2 = ytab[sy2[1]];

		/* first line 00rrrrrr.rr000ggg.ggggg000.bbbbbbbb: */
		*(unsigned int *)(d1+BPP4) =
			(CLIP8[y1 + bu])        |
			(CLIP8[y1 + guv] << 11) |
			(CLIP8[y1 + rv]  << 22) ;

		/* second line 00rrrrrr.rr000ggg.ggggg000.bbbbbbbb: */
		*(unsigned int *)(d2+BPP4) =
			(CLIP8[y2 + bu])        |
			(CLIP8[y2 + guv] << 11) |
			(CLIP8[y2 + rv]  << 22) ;

		/* next 2x2 block */
		sy1 += 2; sy2 += 2;
		su += 1; sv += 1;
		d1 += 2*BPP4; d2 += 2*BPP4;
	}

	/* convert last 2x1 block: */
	if (dx & 1) {

		bu = butab[su[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		rv = rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line 00rrrrrr.rr000ggg.ggggg000.bbbbbbbb: */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + bu])        |
			(CLIP8[y1 + guv] << 11) |
			(CLIP8[y1 + rv]  << 22) ;

		/* second line BGR0 */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + bu])        |
			(CLIP8[y2 + guv] << 11) |
			(CLIP8[y2 + rv]  << 22) ;
	}
}

static void dblineI420toXRGBalpha (unsigned char *d1, unsigned char *d2, int dest_x,
								   unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
								   int src_x, int dx)
{
	register int y1, y2, ruv, guv, buv;
	register int i;

	/* convert first 2x1 block: */
	if (src_x & 1) {

		buv = butab[su[0]] + bvtab[sv[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		ruv = rutab[su[0]] + rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line 00rrrrrr.rr000ggg.ggggg000.bbbbbbbb: */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + buv])       |
			(CLIP8[y1 + guv] << 11) |
			(CLIP8[y1 + ruv] << 22);

		/* second line 00rrrrrr.rr000ggg.ggggg000.bbbbbbbb: */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + buv])       |
			(CLIP8[y2 + guv] << 11) |
			(CLIP8[y2 + ruv] << 22) ;

		sy1 += 1; sy2 += 1;
		su += 1; sv += 1;
		d1 += BPP4; d2 += BPP4;
		dx --;
	}

	/* convert all integral 2x2 blocks: */
	for (i = 0; i < dx/2; i ++) {

		buv = butab[su[0]] + bvtab[sv[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		ruv = rutab[su[0]] + rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line 00rrrrrr.rr000ggg.ggggg000.bbbbbbbb: */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + buv])       |
			(CLIP8[y1 + guv] << 11) |
			(CLIP8[y1 + ruv] << 22) ;

		/* second line 00rrrrrr.rr000ggg.ggggg000.bbbbbbbb: */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + buv])       |
			(CLIP8[y2 + guv] << 11) |
			(CLIP8[y2 + ruv] << 22) ;

		y1 = ytab[sy1[1]];
		y2 = ytab[sy2[1]];

		/* first line 00rrrrrr.rr000ggg.ggggg000.bbbbbbbb: */
		*(unsigned int *)(d1+BPP4) =
			(CLIP8[y1 + buv])       |
			(CLIP8[y1 + guv] << 11) |
			(CLIP8[y1 + ruv] << 22) ;

		/* second line 00rrrrrr.rr000ggg.ggggg000.bbbbbbbb: */
		*(unsigned int *)(d2+BPP4) =
			(CLIP8[y2 + buv])       |
			(CLIP8[y2 + guv] << 11) |
			(CLIP8[y2 + ruv] << 22) ;

		/* next 2x2 block */
		sy1 += 2; sy2 += 2;
		su += 1; sv += 1;
		d1 += 2*BPP4; d2 += 2*BPP4;
	}

	/* convert last 2x1 block: */
	if (dx & 1) {

		buv = butab[su[0]] + bvtab[sv[0]];
		guv = gutab[su[0]] + gvtab[sv[0]];
		ruv = rutab[su[0]] + rvtab[sv[0]];
		y1 = ytab[sy1[0]];
		y2 = ytab[sy2[0]];

		/* first line 00rrrrrr.rr000ggg.ggggg000.bbbbbbbb: */
		*(unsigned int *)(d1+0) =
			(CLIP8[y1 + buv])       |
			(CLIP8[y1 + guv] << 11) |
			(CLIP8[y1 + ruv] << 22) ;

		/* second line 00rrrrrr.rr000ggg.ggggg000.bbbbbbbb: */
		*(unsigned int *)(d2+0) =
			(CLIP8[y2 + buv])       |
			(CLIP8[y2 + guv] << 11) |
			(CLIP8[y2 + ruv] << 22) ;
	}
}

/*
* Interpolate and pack RGB lines into final output
* Produces two output lines per call.
* Requires padded RGB for SIMD interpolation.
*/
#define ROUND888 0x00400801

/* RGB32 version: */
static void dblineXRGBtoRGB32x2 (unsigned char *d1, unsigned char *d2, int dest_x,
								 unsigned char *s1, unsigned char *s2, int src_x, int dx)
{
	register unsigned int a, b, c, d, e, f;
	register unsigned int w, x, y, z;

	/* convert first 2x1 block: */
	if (dest_x & 1) {

		/* Input pels  =>   Output pels
		*  a b             w  x
		*  c d             w' x'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);

		w = a;
		x = a + b + ROUND888;

		/* pack and store */
		*(unsigned int *)(d1+0) =
			((w & 0x000000ff) >> 0) |
			((w & 0x0007f800) >> 3) |
			((w & 0x3fc00000) >> 6);
		*(unsigned int *)(d1+BPP4) =
			((x & 0x000001fe) >> 1) |
			((x & 0x000ff000) >> 4) |
			((x & 0x7f800000) >> 7);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = *(unsigned int *)(s2+BPP4);

		w = a + c + ROUND888;
		x = a + b + c + d + (ROUND888<<1);

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001fe) >> 1) |
			((w & 0x000ff000) >> 4) |
			((w & 0x7f800000) >> 7);
		*(unsigned int *)(d2+BPP4) =
			((x & 0x000003fc) >> 2) |
			((x & 0x001fe000) >> 5) |
			((x & 0xff000000) >> 8);

		/* bump pointers to next block */
		s1 += BPP4; s2 += BPP4;
		d1 += 2*BPP4; d2 += 2*BPP4;
		dx -= 1;
	}

	/* process all integral 2x2 blocks: */
	while (dx > 2) {    /* we need to leave at least one block */

		/*
		* Input stored as 00 RRRRRRRR 000 GGGGGGGG 000 BBBBBBBB
		*
		* Input pels  =>   Output pels
		*  a b e           w  x  y  z
		*  c d f           w' x' y' z'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);
		e = *(unsigned int *)(s1+2*BPP4);

		w = a;
		x = a + b + ROUND888;
		y = b;
		z = b + e + ROUND888;

		/* pack and store */
		*(unsigned int *)d1 =
			((w & 0x000000ff) >> 0) |
			((w & 0x0007f800) >> 3) |
			((w & 0x3fc00000) >> 6);
		*(unsigned int *)(d1+BPP4) =
			((x & 0x000001fe) >> 1) |
			((x & 0x000ff000) >> 4) |
			((x & 0x7f800000) >> 7);
		*(unsigned int *)(d1+2*BPP4) =
			((y & 0x000000ff) >> 0) |
			((y & 0x0007f800) >> 3) |
			((y & 0x3fc00000) >> 6);
		*(unsigned int *)(d1+3*BPP4) =
			((z & 0x000001fe) >> 1) |
			((z & 0x000ff000) >> 4) |
			((z & 0x7f800000) >> 7);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = *(unsigned int *)(s2+BPP4);
		f = *(unsigned int *)(s2+2*BPP4);

		w = a + c + ROUND888;
		x = a + b + c + d + (ROUND888<<1);
		y = b + d + ROUND888;
		z = b + e + d + f + (ROUND888<<1);

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001fe) >> 1) |
			((w & 0x000ff000) >> 4) |
			((w & 0x7f800000) >> 7);
		*(unsigned int *)(d2+BPP4) =
			((x & 0x000003fc) >> 2) |
			((x & 0x001fe000) >> 5) |
			((x & 0xff000000) >> 8);
		*(unsigned int *)(d2+2*BPP4) =
			((y & 0x000001fe) >> 1) |
			((y & 0x000ff000) >> 4) |
			((y & 0x7f800000) >> 7);
		*(unsigned int *)(d2+3*BPP4) =
			((z & 0x000003fc) >> 2) |
			((z & 0x001fe000) >> 5) |
			((z & 0xff000000) >> 8);

		/* bump pointers to next 2x2 input */
		s1 += 2*BPP4; s2 += 2*BPP4;
		d1 += 4*BPP4; d2 += 4*BPP4;
		dx -= 2;
	}

	/* check if this is the last 2x2 block: */
	if (dx > 1) {

		/*
		* For last 4 output pels, repeat final input pel
		* for offscreen input.  Equivalent to pixel-doubling the
		* last output pel.
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);
		e = b;      /* repeat last input pel */
		w = a;

		x = a + b + ROUND888;
		y = b;
		z = b + e + ROUND888;

		/* pack and store */
		*(unsigned int *)d1 =
			((w & 0x000000ff) >> 0) |
			((w & 0x0007f800) >> 3) |
			((w & 0x3fc00000) >> 6);
		*(unsigned int *)(d1+BPP4) =
			((x & 0x000001fe) >> 1) |
			((x & 0x000ff000) >> 4) |
			((x & 0x7f800000) >> 7);
		*(unsigned int *)(d1+2*BPP4) =
			((y & 0x000000ff) >> 0) |
			((y & 0x0007f800) >> 3) |
			((y & 0x3fc00000) >> 6);
		*(unsigned int *)(d1+3*BPP4) =
			((z & 0x000001fe) >> 1) |
			((z & 0x000ff000) >> 4) |
			((z & 0x7f800000) >> 7);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = *(unsigned int *)(s2+BPP4);
		f = d;      /* repeat last input pel */

		w = a + c + ROUND888;
		x = a + b + c + d + (ROUND888<<1);
		y = b + d + ROUND888;
		z = b + e + d + f + (ROUND888<<1);

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001fe) >> 1) |
			((w & 0x000ff000) >> 4) |
			((w & 0x7f800000) >> 7);
		*(unsigned int *)(d2+BPP4) =
			((x & 0x000003fc) >> 2) |
			((x & 0x001fe000) >> 5) |
			((x & 0xff000000) >> 8);
		*(unsigned int *)(d2+2*BPP4) =
			((y & 0x000001fe) >> 1) |
			((y & 0x000ff000) >> 4) |
			((y & 0x7f800000) >> 7);
		*(unsigned int *)(d2+3*BPP4) =
			((z & 0x000003fc) >> 2) |
			((z & 0x001fe000) >> 5) |
			((z & 0xff000000) >> 8);

	} else {
		/* last 2x1 block: */

		/* Input pels  =>   Output pels
		*  a b             w  x
		*  c d             w' x'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = a;      /* repeat last input pel */

		w = a;
		x = a + b + ROUND888;

		/* pack and store */
		*(unsigned int *)(d1+0) =
			((w & 0x000000ff) >> 0) |
			((w & 0x0007f800) >> 3) |
			((w & 0x3fc00000) >> 6);
		*(unsigned int *)(d1+BPP4) =
			((x & 0x000001fe) >> 1) |
			((x & 0x000ff000) >> 4) |
			((x & 0x7f800000) >> 7);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = c;      /* repeat last input pel */

		w = a + c + ROUND888;
		x = a + b + c + d + (ROUND888<<1);

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001fe) >> 1) |
			((w & 0x000ff000) >> 4) |
			((w & 0x7f800000) >> 7);
		*(unsigned int *)(d2+BPP4) =
			((x & 0x000003fc) >> 2) |
			((x & 0x001fe000) >> 5) |
			((x & 0xff000000) >> 8);
	}
}

/* BGR32 version: */

static void dblineXRGBtoBGR32x2 (unsigned char *d1, unsigned char *d2, int dest_x,
								 unsigned char *s1, unsigned char *s2, int src_x, int dx)
{
	register unsigned int a, b, c, d, e, f;
	register unsigned int w, x, y, z;

	/* convert first 2x1 block: */
	if (dest_x & 1) {

		/* Input pels  =>   Output pels
		*  a b             w  x
		*  c d             w' x'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);

		w = a;
		x = a + b + ROUND888;

		/* pack and store */
		*(unsigned int *)(d1+0) =
			((w & 0x000000ff) << 16)|
			((w & 0x0007f800) >> 3) |
			((w & 0x3fc00000) >> 22);
		*(unsigned int *)(d1+BPP4) =
			((x & 0x000001fe) << 15)|
			((x & 0x000ff000) >> 4) |
			((x & 0x7f800000) >> 23);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = *(unsigned int *)(s2+BPP4);

		w = a + c + ROUND888;
		x = a + b + c + d + (ROUND888<<1);

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001fe) << 15)|
			((w & 0x000ff000) >> 4) |
			((w & 0x7f800000) >> 23);
		*(unsigned int *)(d2+BPP4) =
			((x & 0x000003fc) << 14)|
			((x & 0x001fe000) >> 5) |
			((x & 0xff000000) >> 24);

		/* bump pointers to next block */
		s1 += BPP4; s2 += BPP4;
		d1 += 2*BPP4; d2 += 2*BPP4;
		dx -= 1;
	}

	/* process all integral 2x2 blocks: */
	while (dx > 2) {    /* we need to leave at least one block */

		/*
		* Input stored as 00 RRRRRRRR 000 GGGGGGGG 000 BBBBBBBB
		*
		* Input pels  =>   Output pels
		*  a b e           w  x  y  z
		*  c d f           w' x' y' z'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);
		e = *(unsigned int *)(s1+2*BPP4);

		w = a;
		x = a + b + ROUND888;
		y = b;
		z = b + e + ROUND888;

		/* pack and store */
		*(unsigned int *)d1 =
			((w & 0x000000ff) << 16)|
			((w & 0x0007f800) >> 3) |
			((w & 0x3fc00000) >> 22);
		*(unsigned int *)(d1+BPP4) =
			((x & 0x000001fe) << 15)|
			((x & 0x000ff000) >> 4) |
			((x & 0x7f800000) >> 23);
		*(unsigned int *)(d1+2*BPP4) =
			((y & 0x000000ff) << 16)|
			((y & 0x0007f800) >> 3) |
			((y & 0x3fc00000) >> 22);
		*(unsigned int *)(d1+3*BPP4) =
			((z & 0x000001fe) << 15)|
			((z & 0x000ff000) >> 4) |
			((z & 0x7f800000) >> 23);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = *(unsigned int *)(s2+BPP4);
		f = *(unsigned int *)(s2+2*BPP4);

		w = a + c + ROUND888;
		x = a + b + c + d + (ROUND888<<1);
		y = b + d + ROUND888;
		z = b + e + d + f + (ROUND888<<1);

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001fe) << 15)|
			((w & 0x000ff000) >> 4) |
			((w & 0x7f800000) >> 23);
		*(unsigned int *)(d2+BPP4) =
			((x & 0x000003fc) << 14)|
			((x & 0x001fe000) >> 5) |
			((x & 0xff000000) >> 24);
		*(unsigned int *)(d2+2*BPP4) =
			((y & 0x000001fe) << 15)|
			((y & 0x000ff000) >> 4) |
			((y & 0x7f800000) >> 23);
		*(unsigned int *)(d2+3*BPP4) =
			((z & 0x000003fc) << 14)|
			((z & 0x001fe000) >> 5) |
			((z & 0xff000000) >> 24);

		/* bump pointers to next 2x2 input */
		s1 += 2*BPP4; s2 += 2*BPP4;
		d1 += 4*BPP4; d2 += 4*BPP4;
		dx -= 2;
	}

	/* check if this is the last 2x2 block: */
	if (dx > 1) {

		/*
		* For last 4 output pels, repeat final input pel
		* for offscreen input.  Equivalent to pixel-doubling the
		* last output pel.
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);
		e = b;      /* repeat last input pel */
		w = a;

		x = a + b + ROUND888;
		y = b;
		z = b + e + ROUND888;

		/* pack and store */
		*(unsigned int *)d1 =
			((w & 0x000000ff) << 16)|
			((w & 0x0007f800) >> 3) |
			((w & 0x3fc00000) >> 22);
		*(unsigned int *)(d1+BPP4) =
			((x & 0x000001fe) << 15)|
			((x & 0x000ff000) >> 4) |
			((x & 0x7f800000) >> 23);
		*(unsigned int *)(d1+2*BPP4) =
			((y & 0x000000ff) << 16)|
			((y & 0x0007f800) >> 3) |
			((y & 0x3fc00000) >> 22);
		*(unsigned int *)(d1+3*BPP4) =
			((z & 0x000001fe) << 15)|
			((z & 0x000ff000) >> 4) |
			((z & 0x7f800000) >> 23);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = *(unsigned int *)(s2+BPP4);
		f = d;      /* repeat last input pel */

		w = a + c + ROUND888;
		x = a + b + c + d + (ROUND888<<1);
		y = b + d + ROUND888;
		z = b + e + d + f + (ROUND888<<1);

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001fe) << 15)|
			((w & 0x000ff000) >> 4) |
			((w & 0x7f800000) >> 23);
		*(unsigned int *)(d2+BPP4) =
			((x & 0x000003fc) << 14)|
			((x & 0x001fe000) >> 5) |
			((x & 0xff000000) >> 24);
		*(unsigned int *)(d2+2*BPP4) =
			((y & 0x000001fe) << 15)|
			((y & 0x000ff000) >> 4) |
			((y & 0x7f800000) >> 23);
		*(unsigned int *)(d2+3*BPP4) =
			((z & 0x000003fc) << 14)|
			((z & 0x001fe000) >> 5) |
			((z & 0xff000000) >> 24);

	} else {
		/* last 2x1 block: */

		/* Input pels  =>   Output pels
		*  a b             w  x
		*  c d             w' x'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = a;      /* repeat last input pel */

		w = a;
		x = a + b + ROUND888;

		/* pack and store */
		*(unsigned int *)(d1+0) =
			((w & 0x000000ff) << 16)|
			((w & 0x0007f800) >> 3) |
			((w & 0x3fc00000) >> 22);
		*(unsigned int *)(d1+BPP4) =
			((x & 0x000001fe) << 15)|
			((x & 0x000ff000) >> 4) |
			((x & 0x7f800000) >> 23);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = c;      /* repeat last input pel */

		w = a + c + ROUND888;
		x = a + b + c + d + (ROUND888<<1);

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001fe) << 15)|
			((w & 0x000ff000) >> 4) |
			((w & 0x7f800000) >> 23);
		*(unsigned int *)(d2+BPP4) =
			((x & 0x000003fc) << 14)|
			((x & 0x001fe000) >> 5) |
			((x & 0xff000000) >> 24);
	}
}

/* RGB24 version: */
static void dblineXRGBtoRGB24x2 (unsigned char *d1, unsigned char *d2, int dest_x,
								 unsigned char *s1, unsigned char *s2, int src_x, int dx)
{
	register unsigned int a, b, c, d, e, f;
	register unsigned int w, x, y, z;

	/* convert first 2x1 block: */
	if (dest_x & 1) {

		/* Input pels  =>   Output pels
		*  a b             w  x
		*  c d             w' x'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);

		w = a;
		x = a + b + ROUND888;

		/* pack and store */
		*(unsigned int *)d1 =           /* brgB */
			((w & 0x000000ff) >> 0)  |
			((w & 0x0007f800) >> 3)  |
			((w & 0x3fc00000) >> 6)  |
			((x & 0x000001fe) << 23);
		*(unsigned short *)(d1+4) =     /* GR */
			((x & 0x000ff000) >> 12) |
			((x & 0x7f800000) >> 15);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = *(unsigned int *)(s2+BPP4);

		w = a + c + ROUND888;
		x = a + b + c + d + (ROUND888<<1);

		/* pack and store */
		*(unsigned int *)d2 =           /* bgrB */
			((w & 0x000001fe) >> 1)  |
			((w & 0x000ff000) >> 4)  |
			((w & 0x7f800000) >> 7)  |
			((x & 0x000003fc) << 22);
		*(unsigned short *)(d2+4) =     /* GR */
			((x & 0x001fe000) >> 13) |
			((x & 0xff000000) >> 16);

		/* bump pointers to next block */
		s1 += BPP4; s2 += BPP4;
		d1 += 2*BPP3; d2 += 2*BPP3;
		dx -= 1;
	}

	/* process all integral 2x2 blocks: */
	while (dx > 2) {    /* we need to leave at least one block */

		/*
		* Input stored as 00 RRRRRRRR 000 GGGGGGGG 000 BBBBBBBB
		*
		* Input pels  =>   Output pels
		*  a b e           w  x  y  z
		*  c d f           w' x' y' z'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);
		e = *(unsigned int *)(s1+2*BPP4);

		w = a;
		x = a + b + ROUND888;
		y = b;
		z = b + e + ROUND888;

		/* pack and store */
		*(unsigned int *)d1 =           /* brgB */
			((w & 0x000000ff) >> 0)  |
			((w & 0x0007f800) >> 3)  |
			((w & 0x3fc00000) >> 6)  |
			((x & 0x000001fe) << 23);
		*(unsigned int *)(d1+4) =       /* GRbg */
			((x & 0x000ff000) >> 12) |
			((x & 0x7f800000) >> 15) |
			((y & 0x000000ff) << 16) |
			((y & 0x0007f800) << 13);
		*(unsigned int *)(d1+8) =       /* rBGR */
			((y & 0x3fc00000) >> 22) |
			((z & 0x000001fe) << 7)  |
			((z & 0x000ff000) << 4)  |
			((z & 0x7f800000) << 1);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = *(unsigned int *)(s2+BPP4);
		f = *(unsigned int *)(s2+2*BPP4);

		w = a + c + ROUND888;
		x = a + b + c + d + (ROUND888<<1);
		y = b + d + ROUND888;
		z = b + e + d + f + (ROUND888<<1);

		/* pack and store */
		*(unsigned int *)d2 =           /* bgrB */
			((w & 0x000001fe) >> 1)  |
			((w & 0x000ff000) >> 4)  |
			((w & 0x7f800000) >> 7)  |
			((x & 0x000003fc) << 22);
		*(unsigned int *)(d2+4) =       /* GRbg */
			((x & 0x001fe000) >> 13) |
			((x & 0xff000000) >> 16) |
			((y & 0x000001fe) << 15) |
			((y & 0x000ff000) << 12);
		*(unsigned int *)(d2+8) =       /* rBGR */
			((y & 0x7f800000) >> 23) |
			((z & 0x000003fc) << 6)  |
			((z & 0x001fe000) << 3)  |
			((z & 0xff000000) << 0);

		/* next 2x2 input block */
		s1 += 2*BPP4; s2 += 2*BPP4;
		d1 += 4*BPP3; d2 += 4*BPP3;
		dx -= 2;
	}

	/* check if this is the last 2x2 block: */
	if (dx > 1) {

		/*
		* For last 4 output pels, repeat final input pel
		* for offscreen input.  Equivalent to pixel-doubling the
		* last output pel.
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);
		e = b;      /* repeat last input pel */

		w = a;
		x = a + b + ROUND888;
		y = b;
		z = b + e + ROUND888;

		/* pack and store */
		*(unsigned int *)(d1+0) =       /* bgrB */
			((w & 0x000000ff) >> 0)  |
			((w & 0x0007f800) >> 3)  |
			((w & 0x3fc00000) >> 6)  |
			((x & 0x000001fe) << 23);
		*(unsigned int *)(d1+4) =       /* GRbg */
			((x & 0x000ff000) >> 12) |
			((x & 0x7f800000) >> 15) |
			((y & 0x000000ff) << 16) |
			((y & 0x0007f800) << 13);
		*(unsigned int *)(d1+8) =       /* rBGR */
			((y & 0x3fc00000) >> 22) |
			((z & 0x000001fe) << 7)  |
			((z & 0x000ff000) << 4)  |
			((z & 0x7f800000) << 1);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = *(unsigned int *)(s2+BPP4);
		f = d;      /* repeat last input pel */

		w = a + c + ROUND888;
		x = a + b + c + d + (ROUND888<<1);
		y = b + d + ROUND888;
		z = b + e + d + f + (ROUND888<<1);

		/* pack and store */
		*(unsigned int *)(d2+0) =       /* bgrB */
			((w & 0x000001fe) >> 1)  |
			((w & 0x000ff000) >> 4)  |
			((w & 0x7f800000) >> 7)  |
			((x & 0x000003fc) << 22);
		*(unsigned int *)(d2+4) =       /* GRbg */
			((x & 0x001fe000) >> 13) |
			((x & 0xff000000) >> 16) |
			((y & 0x000001fe) << 15) |
			((y & 0x000ff000) << 12);
		*(unsigned int *)(d2+8) =       /* rBGR */
			((y & 0x7f800000) >> 23) |
			((z & 0x000003fc) << 6)  |
			((z & 0x001fe000) << 3)  |
			((z & 0xff000000) << 0);

	} else {
		/* last 2x1 block: */

		/* Input pels  =>   Output pels
		*  a b             w  x
		*  c d             w' x'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = a;      /* repeat last input pel */

		w = a;
		x = a + b + ROUND888;

		/* pack and store */
		*(unsigned int *)d1 =           /* brgB */
			((w & 0x000000ff) >> 0)  |
			((w & 0x0007f800) >> 3)  |
			((w & 0x3fc00000) >> 6)  |
			((x & 0x000001fe) << 23);
		*(unsigned short *)(d1+4) =     /* GR */
			((x & 0x000ff000) >> 12) |
			((x & 0x7f800000) >> 15);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = c;      /* repeat last input pel */

		w = a + c + ROUND888;
		x = a + b + c + d + (ROUND888<<1);

		/* pack and store */
		*(unsigned int *)d2 =           /* bgrB */
			((w & 0x000001fe) >> 1)  |
			((w & 0x000ff000) >> 4)  |
			((w & 0x7f800000) >> 7)  |
			((x & 0x000003fc) << 22);
		*(unsigned short *)(d2+4) =     /* GR */
			((x & 0x001fe000) >> 13) |
			((x & 0xff000000) >> 16);
	}
}

/* RGB565 version: */
static void dblineXRGBtoRGB565x2 (unsigned char *d1, unsigned char *d2, int dest_x,
								  unsigned char *s1, unsigned char *s2, int src_x, int dx)
{
	register unsigned int a, b, c, d, e, f;
	register unsigned int w, x, y, z;

	/* convert first 2x1 block: */
	if (dest_x & 1) {

		/* Input pels  =>   Output pels
		*  a b             w  x
		*  c d             w' x'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);

		w = a;
		x = a + b;

		/* pack and store */
		*(unsigned int *)d1 =
			((w & 0x000000f8) >> 3)  |
			((w & 0x0007e000) >> 8)  |
			((w & 0x3e000000) >> 14) |
			((x & 0x000001f0) << 12) |
			((x & 0x000fc000) << 7)  |
			((x & 0x7c000000) << 1);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = *(unsigned int *)(s2+BPP4);

		w = a + c;
		x = a + b + c + d;

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001f0) >> 4)  |
			((w & 0x000fc000) >> 9)  |
			((w & 0x7c000000) >> 15) |
			((x & 0x000003e0) << 11) |
			((x & 0x001f8000) << 6)  |
			((x & 0xf8000000) << 0);

		/* bump pointers to next block */
		s1 += BPP4; s2 += BPP4;
		d1 += 2*BPP2; d2 += 2*BPP2;
		dx -= 1;
	}

	/* process all integral 2x2 blocks: */
	while (dx > 2) {    /* we need to leave at least one block */

		/*
		* Input stored as 00 RRRRRRRR 000 GGGGGGGG 000 BBBBBBBB
		*
		* Input pels       Output pels
		*  a b e           w  x  y  z
		*  c d f           w' x' y' z'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);
		e = *(unsigned int *)(s1+2*BPP4);

		w = a;
		x = a + b;
		y = b;
		z = b + e;

		/* pack and store */
		*(unsigned int *)d1 =
			((w & 0x000000f8) >> 3)  |
			((w & 0x0007e000) >> 8)  |
			((w & 0x3e000000) >> 14) |
			((x & 0x000001f0) << 12) |
			((x & 0x000fc000) << 7)  |
			((x & 0x7c000000) << 1);
		*(unsigned int *)(d1+2*BPP2) =
			((y & 0x000000f8) >> 3)  |
			((y & 0x0007e000) >> 8)  |
			((y & 0x3e000000) >> 14) |
			((z & 0x000001f0) << 12) |
			((z & 0x000fc000) << 7)  |
			((z & 0x7c000000) << 1);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = *(unsigned int *)(s2+BPP4);
		f = *(unsigned int *)(s2+2*BPP4);

		w = a + c;
		x = a + b + c + d;
		y = b + d;
		z = b + e + d + f;

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001f0) >> 4)  |
			((w & 0x000fc000) >> 9)  |
			((w & 0x7c000000) >> 15) |
			((x & 0x000003e0) << 11) |
			((x & 0x001f8000) << 6)  |
			((x & 0xf8000000) << 0);
		*(unsigned int *)(d2+2*BPP2) =
			((y & 0x000001f0) >> 4)  |
			((y & 0x000fc000) >> 9)  |
			((y & 0x7c000000) >> 15) |
			((z & 0x000003e0) << 11) |
			((z & 0x001f8000) << 6)  |
			((z & 0xf8000000) << 0);

		/* next 2x2 input block */
		s1 += 2*BPP4; s2 += 2*BPP4;
		d1 += 4*BPP2; d2 += 4*BPP2;
		dx -= 2;
	}

	/* check if this is the last 2x2 block: */
	if (dx > 1) {

		/*
		* For last 4 output pels, repeat final input pel
		* for offscreen input.  Equivalent to pixel-doubling the
		* last output pel.
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);
		e = b;      /* repeat last input pel */

		w = a;
		x = a + b;
		y = b;
		z = b + e;

		/* pack and store */
		*(unsigned int *)d1 =
			((w & 0x000000f8) >> 3)  |
			((w & 0x0007e000) >> 8)  |
			((w & 0x3e000000) >> 14) |
			((x & 0x000001f0) << 12) |
			((x & 0x000fc000) << 7)  |
			((x & 0x7c000000) << 1);
		*(unsigned int *)(d1+2*BPP2) =
			((y & 0x000000f8) >> 3)  |
			((y & 0x0007e000) >> 8)  |
			((y & 0x3e000000) >> 14) |
			((z & 0x000001f0) << 12) |
			((z & 0x000fc000) << 7)  |
			((z & 0x7c000000) << 1);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = *(unsigned int *)(s2+BPP4);
		f = d;      /* repeat last input pel */

		w = a + c;
		x = a + b + c + d;
		y = b + d;
		z = b + e + d + f;

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001f0) >> 4)  |
			((w & 0x000fc000) >> 9)  |
			((w & 0x7c000000) >> 15) |
			((x & 0x000003e0) << 11) |
			((x & 0x001f8000) << 6)  |
			((x & 0xf8000000) << 0);
		*(unsigned int *)(d2+2*BPP2) =
			((y & 0x000001f0) >> 4)  |
			((y & 0x000fc000) >> 9)  |
			((y & 0x7c000000) >> 15) |
			((z & 0x000003e0) << 11) |
			((z & 0x001f8000) << 6)  |
			((z & 0xf8000000) << 0);

	} else {
		/* last 2x1 block: */

		/* Input pels  =>   Output pels
		*  a b             w  x
		*  c d             w' x'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = a;      /* repeat last input pel */

		w = a;
		x = a + b;

		/* pack and store */
		*(unsigned int *)d1 =
			((w & 0x000000f8) >> 3)  |
			((w & 0x0007e000) >> 8)  |
			((w & 0x3e000000) >> 14) |
			((x & 0x000001f0) << 12) |
			((x & 0x000fc000) << 7)  |
			((x & 0x7c000000) << 1);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = c;      /* repeat last input pel */

		w = a + c;
		x = a + b + c + d;

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001f0) >> 4)  |
			((w & 0x000fc000) >> 9)  |
			((w & 0x7c000000) >> 15) |
			((x & 0x000003e0) << 11) |
			((x & 0x001f8000) << 6)  |
			((x & 0xf8000000) << 0);
	}
}

/* RGB555 version: */
static void dblineXRGBtoRGB555x2 (unsigned char *d1, unsigned char *d2, int dest_x,
								  unsigned char *s1, unsigned char *s2, int src_x, int dx)
{
	register unsigned int a, b, c, d, e, f;
	register unsigned int w, x, y, z;

	/* convert first 2x1 block: */
	if (dest_x & 1) {

		/* Input pels  =>   Output pels
		*  a b             w  x
		*  c d             w' x'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);

		w = a;
		x = a + b;

		/* pack and store */
		/* pack and store */
		*(unsigned int *)d1 =
			((w & 0x000000f8) >> 3)  |
			((w & 0x0007c000) >> 9)  |
			((w & 0x3e000000) >> 15) |
			((x & 0x000001f0) << 12) |
			((x & 0x000f8000) << 6)  |
			((x & 0x7c000000) << 0);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = *(unsigned int *)(s2+BPP4);

		w = a + c;
		x = a + b + c + d;

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001f0) >> 4)  |
			((w & 0x000f8000) >> 10) |
			((w & 0x7c000000) >> 16) |
			((x & 0x000003e0) << 11) |
			((x & 0x001f0000) << 5)  |
			((x & 0xf8000000) >> 1);

		/* bump pointers to next block */
		s1 += BPP4; s2 += BPP4;
		d1 += 2*BPP2; d2 += 2*BPP2;
		dx -= 1;
	}

	/* process all integral 2x2 blocks: */
	while (dx > 2) {    /* we need to leave at least one block */

		/*
		* Input pels       Output pels
		*  a b e           w  x  y  z
		*  c d f           w' x' y' z'
		*
		* Input stored as 00 RRRRRRRR 000 GGGGGGGG 000 BBBBBBBB
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);
		e = *(unsigned int *)(s1+2*BPP4);

		w = a;
		x = a + b;
		y = b;
		z = b + e;

		/* pack and store */
		*(unsigned int *)d1 =
			((w & 0x000000f8) >> 3)  |
			((w & 0x0007c000) >> 9)  |
			((w & 0x3e000000) >> 15) |
			((x & 0x000001f0) << 12) |
			((x & 0x000f8000) << 6)  |
			((x & 0x7c000000) << 0);
		*(unsigned int *)(d1+BPP4) =
			((y & 0x000000f8) >> 3)  |
			((y & 0x0007c000) >> 9)  |
			((y & 0x3e000000) >> 15) |
			((z & 0x000001f0) << 12) |
			((z & 0x000f8000) << 6)  |
			((z & 0x7c000000) << 0);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = *(unsigned int *)(s2+BPP4);
		f = *(unsigned int *)(s2+2*BPP4);

		w = a + c;
		x = a + b + c + d;
		y = b + d;
		z = b + e + d + f;

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001f0) >> 4)  |
			((w & 0x000f8000) >> 10) |
			((w & 0x7c000000) >> 16) |
			((x & 0x000003e0) << 11) |
			((x & 0x001f0000) << 5)  |
			((x & 0xf8000000) >> 1);
		*(unsigned int *)(d2+BPP4) =
			((y & 0x000001f0) >> 4)  |
			((y & 0x000f8000) >> 10) |
			((y & 0x7c000000) >> 16) |
			((z & 0x000003e0) << 11) |
			((z & 0x001f0000) << 5)  |
			((z & 0xf8000000) >> 1);

		/* next 2x2 input block */
		s1 += 2*BPP4; s2 += 2*BPP4;
		d1 += 4*BPP2; d2 += 4*BPP2;
		dx -= 2;
	}

	/* check if this is the last 2x2 block: */
	if (dx > 1) {

		/*
		* For last 4 output pels, repeat final input pel
		* for offscreen input.  Equivalent to pixel-doubling the
		* last output pel.
		*/

		/* top line */
		a = *(unsigned int *)(s1+0);
		b = *(unsigned int *)(s1+4);
		e = b;      /* repeat last input pel */
		w = a;

		x = a + b;
		y = b;
		z = b + e;

		/* pack and store */
		*(unsigned int *)d1 =
			((w & 0x000000f8) >> 3)  |
			((w & 0x0007c000) >> 9)  |
			((w & 0x3e000000) >> 15) |
			((x & 0x000001f0) << 12) |
			((x & 0x000f8000) << 6)  |
			((x & 0x7c000000) << 0);
		*(unsigned int *)(d1+BPP4) =
			((y & 0x000000f8) >> 3)  |
			((y & 0x0007c000) >> 9)  |
			((y & 0x3e000000) >> 15) |
			((z & 0x000001f0) << 12) |
			((z & 0x000f8000) << 6)  |
			((z & 0x7c000000) << 0);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = *(unsigned int *)(s2+BPP4);
		f = d;      /* repeat last input pel */
		w = a + c;

		x = a + b + c + d;
		y = b + d;
		z = b + e + d + f;

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001f0) >> 4)  |
			((w & 0x000f8000) >> 10) |
			((w & 0x7c000000) >> 16) |
			((x & 0x000003e0) << 11) |
			((x & 0x001f0000) << 5)  |
			((x & 0xf8000000) >> 1);
		*(unsigned int *)(d2+2*BPP2) =
			((y & 0x000001f0) >> 4)  |
			((y & 0x000f8000) >> 10) |
			((y & 0x7c000000) >> 16) |
			((z & 0x000003e0) << 11) |
			((z & 0x001f0000) << 5)  |
			((z & 0xf8000000) >> 1);

	} else {
		/* last 2x1 block: */

		/* Input pels  =>   Output pels
		*  a b             w  x
		*  c d             w' x'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = a;      /* repeat last input pel */

		w = a;
		x = a + b;

		/* pack and store */
		*(unsigned int *)d1 =
			((w & 0x000000f8) >> 3)  |
			((w & 0x0007c000) >> 9)  |
			((w & 0x3e000000) >> 15) |
			((x & 0x000001f0) << 12) |
			((x & 0x000f8000) << 6)  |
			((x & 0x7c000000) << 0);

		/* bottom line */
		c = *(unsigned int *)s2;
		d = c;      /* repeat last input pel */

		w = a + c;
		x = a + b + c + d;

		/* pack and store */
		*(unsigned int *)d2 =
			((w & 0x000001f0) >> 4)  |
			((w & 0x000f8000) >> 10) |
			((w & 0x7c000000) >> 16) |
			((x & 0x000003e0) << 11) |
			((x & 0x001f0000) << 5)  |
			((x & 0xf8000000) >> 1);
	}
}

/* RGB8 version: */
static void dblineXRGBtoRGB8x2 (unsigned char *d1, unsigned char *d2, int dest_x,
								unsigned char *s1, unsigned char *s2, int src_x, int dx)
{
	register unsigned int a, b, c, d, e, f;
	register unsigned int w, x, y, z;

	/* convert first 2x1 block: */
	if (dest_x & 1) {

		/* Input pels  =>   Output pels
		*  a b             w  x
		*  c d             w' x'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);

		w = a;
		x = a + b + ROUND888;

		/* pack and store */
		*(d1+0) = pmap[
			((w & 0x000000f0) >> 4)  |
				((w & 0x00078000) >> 11) |
				((w & 0x3c000000) >> 18)];
			*(d1+BPP1) = pmap[
				((x & 0x000001e0) >> 5)  |
					((x & 0x000f0000) >> 12) |
					((x & 0x78000000) >> 19)];

				/* bottom line */
				c = *(unsigned int *)s2;
				d = *(unsigned int *)(s2+BPP4);

				w = a + c + ROUND888;
				x = a + b + c + d + (ROUND888<<1);

				/* pack and store */
				*(d2+0) = pmap[
					((w & 0x000001e0) >> 5)  |
						((w & 0x000f0000) >> 12) |
						((w & 0x78000000) >> 19)];
					*(d2+BPP1) = pmap[
						((x & 0x000003c0) >> 6)  |
							((x & 0x001e0000) >> 13) |
							((x & 0xf0000000) >> 20)];

						/* bump pointers to next block */
						s1 += BPP4; s2 += BPP4;
						d1 += 2*BPP1; d2 += 2*BPP1;
						dx -= 1;
	}

	/* process all integral 2x2 blocks: */
	while (dx > 2) {    /* we need to leave at least one block */

		/*
		* Input stored as 00 RRRRRRRR 000 GGGGGGGG 000 BBBBBBBB
		*
		* Input pels  =>   Output pels
		*  a b e           w  x  y  z
		*  c d f           w' x' y' z'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);
		e = *(unsigned int *)(s1+2*BPP4);

		w = a;
		x = a + b + ROUND888;
		y = b;
		z = b + e + ROUND888;

		/* pack and store */
		*(d1+0) = pmap[
			((w & 0x000000f0) >> 4)  |
				((w & 0x00078000) >> 11) |
				((w & 0x3c000000) >> 18)];
			*(d1+BPP1) = pmap[
				((x & 0x000001e0) >> 5)  |
					((x & 0x000f0000) >> 12) |
					((x & 0x78000000) >> 19)];
				*(d1+2*BPP1) = pmap[
					((y & 0x000000f0) >> 4)  |
						((y & 0x00078000) >> 11) |
						((y & 0x3c000000) >> 18)];
					*(d1+3*BPP1) = pmap[
						((z & 0x000001e0) >> 5)  |
							((z & 0x000f0000) >> 12) |
							((z & 0x78000000) >> 19)];

						/* bottom line */
						c = *(unsigned int *)s2;
						d = *(unsigned int *)(s2+BPP4);
						f = *(unsigned int *)(s2+2*BPP4);

						w = a + c + ROUND888;
						x = a + b + c + d + (ROUND888<<1);
						y = b + d + ROUND888;
						z = b + e + d + f + (ROUND888<<1);

						/* pack and store */
						*(d2+0) = pmap[
							((w & 0x000001e0) >> 5)  |
								((w & 0x000f0000) >> 12) |
								((w & 0x78000000) >> 19)];
							*(d2+BPP1) = pmap[
								((x & 0x000003c0) >> 6)  |
									((x & 0x001e0000) >> 13) |
									((x & 0xf0000000) >> 20)];
								*(d2+2*BPP1) = pmap[
									((y & 0x000001e0) >> 5)  |
										((y & 0x000f0000) >> 12) |
										((y & 0x78000000) >> 19)];
									*(d2+3*BPP1) = pmap[
										((z & 0x000003c0) >> 6)  |
											((z & 0x001e0000) >> 13) |
											((z & 0xf0000000) >> 20)];

										/* bump pointers to next 2x2 input */
										s1 += 2*BPP4; s2 += 2*BPP4;
										d1 += 4*BPP1; d2 += 4*BPP1;
										dx -= 2;
	}

	/* check if this is the last 2x2 block: */
	if (dx > 1) {

		/*
		* For last 4 output pels, repeat final input pel
		* for offscreen input.  Equivalent to pixel-doubling the
		* last output pel.
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = *(unsigned int *)(s1+BPP4);
		e = b;      /* repeat last input pel */
		w = a;

		x = a + b + ROUND888;
		y = b;
		z = b + e + ROUND888;

		/* pack and store */
		*(d1+0) = pmap[
			((w & 0x000000f0) >> 4)  |
				((w & 0x00078000) >> 11) |
				((w & 0x3c000000) >> 18)];
			*(d1+BPP1) = pmap[
				((x & 0x000001e0) >> 5)  |
					((x & 0x000f0000) >> 12) |
					((x & 0x78000000) >> 19)];
				*(d1+2*BPP1) = pmap[
					((y & 0x000000f0) >> 4)  |
						((y & 0x00078000) >> 11) |
						((y & 0x3c000000) >> 18)];
					*(d1+3*BPP1) = pmap[
						((z & 0x000001e0) >> 5)  |
							((z & 0x000f0000) >> 12) |
							((z & 0x78000000) >> 19)];

						/* bottom line */
						c = *(unsigned int *)s2;
						d = *(unsigned int *)(s2+BPP4);
						f = d;      /* repeat last input pel */

						w = a + c + ROUND888;
						x = a + b + c + d + (ROUND888<<1);
						y = b + d + ROUND888;
						z = b + e + d + f + (ROUND888<<1);

						/* pack and store */
						*(d2+0) = pmap[
							((w & 0x000001e0) >> 5)  |
								((w & 0x000f0000) >> 12) |
								((w & 0x78000000) >> 19)];
							*(d2+BPP1) = pmap[
								((x & 0x000003c0) >> 6)  |
									((x & 0x001e0000) >> 13) |
									((x & 0xf0000000) >> 20)];
								*(d2+2*BPP1) = pmap[
									((y & 0x000001e0) >> 5)  |
										((y & 0x000f0000) >> 12) |
										((y & 0x78000000) >> 19)];
									*(d2+3*BPP1) = pmap[
										((z & 0x000003c0) >> 6)  |
											((z & 0x001e0000) >> 13) |
											((z & 0xf0000000) >> 20)];

	} else {
		/* last 2x1 block: */

		/* Input pels  =>   Output pels
		*  a b             w  x
		*  c d             w' x'
		*/

		/* top line */
		a = *(unsigned int *)s1;
		b = a;      /* repeat last input pel */

		w = a;
		x = a + b + ROUND888;

		/* pack and store */
		*(d1+0) = pmap[
			((w & 0x000000f0) >> 4)  |
				((w & 0x00078000) >> 11) |
				((w & 0x3c000000) >> 18)];
			*(d1+BPP1) = pmap[
				((x & 0x000001e0) >> 5)  |
					((x & 0x000f0000) >> 12) |
					((x & 0x78000000) >> 19)];

				/* bottom line */
				c = *(unsigned int *)s2;
				d = c;      /* repeat last input pel */

				w = a + c + ROUND888;
				x = a + b + c + d + (ROUND888<<1);

				/* pack and store */
				*(d2+0) = pmap[
					((w & 0x000001e0) >> 5)  |
						((w & 0x000f0000) >> 12) |
						((w & 0x78000000) >> 19)];
					*(d2+BPP1) = pmap[
						((x & 0x000003c0) >> 6)  |
							((x & 0x001e0000) >> 13) |
							((x & 0xf0000000) >> 20)];
	}
}


/* color converter tables: */
static void (* cc []) (unsigned char *d1, unsigned char *d2, int dest_x,
					   unsigned char *sy1, unsigned char *sy2, unsigned char *su,
					   unsigned char *sv, int src_x, int dx) = {
						   dblineI420toRGB32, dblineI420toRGB24,
						   dblineI420toRGB565, dblineI420toRGB555,
						   dblineI420toRGB8, dblineI420toBGR32
};
static void (* ccalpha []) (unsigned char *d1, unsigned char *d2, int dest_x,
							unsigned char *sy1, unsigned char *sy2, unsigned char *su,
							unsigned char *sv, int src_x, int dx) = {
								dblineI420toRGB32alpha, dblineI420toRGB24alpha,
								dblineI420toRGB565alpha, dblineI420toRGB555alpha,
								dblineI420toRGB8alpha, dblineI420toBGR32alpha
};
static void (* ccx2 []) (unsigned char *d1, unsigned char *d2, int dest_x,
						 unsigned char *s1, unsigned char *s2, int src_x, int dx) = {
							 dblineXRGBtoRGB32x2, dblineXRGBtoRGB24x2,
							 dblineXRGBtoRGB565x2, dblineXRGBtoRGB555x2,
							 dblineXRGBtoRGB8x2, dblineXRGBtoBGR32x2
};
static int bpp [] = {4, 3, 2, 2, 1, 4};

/* RGB linebuffers */
static int next[3] = {1, 2, 0};                 /* (ibuf+1)%3 table */
static int next2[3] = {2, 0, 1};                /* (ibuf+2)%3 table */
#define MAXWIDTH 640                            /* max input width */
static unsigned char linebuf [3*MAXWIDTH*BPP4]; /* space for 3 RGB linebuffers */ /* Flawfinder: ignore */

/*
* I420->RGB* driver:
*/
static int I420toRGB (unsigned char *dest_ptr, int dest_width, int dest_height,
					  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
					  unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
					  int src_x, int src_y, int src_dx, int src_dy, int ccidx)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottop-up images: */
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;
	if (src_pitch <= 0) return -1;          /* not supported */

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* color converter to use: */
		void (*dbline) (unsigned char *d1, unsigned char *d2, int dest_x,
			unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
			int src_x, int dx) = is_alpha? ccalpha [ccidx]: cc [ccidx];

		/* local variables: */
		unsigned char *sy1, *sy2, *su, *sv, *d1, *d2;
		register int j;

		/* get pointers: */
		sy1 = src_ptr + (src_x + src_y * src_pitch);        /* luma offset */
		sy2 = sy1 + src_pitch;
		su  = src_ptr + src_height * src_pitch + (src_x/2 + src_y/2 * src_pitch);
		sv  = su + src_height * src_pitch / 4;
		d1  = dest_ptr + dest_x * bpp [ccidx] + dest_y * dest_pitch; /* RGB offset */
		d2  = d1 + dest_pitch;

		/* convert a top line: */
		if (src_y & 1) {                        /* chroma shift */

			/* this is a bit inefficient, but who cares??? */
			(* dbline) (d1, d1, dest_x, sy1, sy1, su, sv, src_x, src_dx);

			sy1 += src_pitch;   sy2 += src_pitch;
			su  += src_pitch/2; sv  += src_pitch/2;
			d1  += dest_pitch;  d2  += dest_pitch;
			dest_dy --;
		}

		/* convert aligned portion of the image: */
		for (j = 0; j < dest_dy/2; j ++) {

			/* convert two lines a time: */
			(* dbline) (d1, d2, dest_x, sy1, sy2, su, sv, src_x, src_dx);

			sy1 += src_pitch*2; sy2 += src_pitch*2;
			su  += src_pitch/2; sv  += src_pitch/2;
			d1  += dest_pitch*2; d2 += dest_pitch*2;
		}

		/* convert bottom line (if dest_dy is odd): */
		if (dest_dy & 1) {

			/* convert one line only: */
			(* dbline) (d1, d1, dest_x, sy1, sy1, su, sv, src_x, src_dx);
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* color converter & interpolator to use: */
		void (*cvt) (unsigned char *d1, unsigned char *d2, int dest_x,
			unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
			int src_x, int dx) = is_alpha? dblineI420toXRGBalpha: dblineI420toXRGB;
		void (*x2) (unsigned char *d1, unsigned char *d2, int dest_x,
			unsigned char *s1, unsigned char *s2, int src_x, int dx) = ccx2 [ccidx];

		/* local variables: */
		unsigned char *sy1, *sy2, *su, *sv, *d1, *d2;
		register int dy = src_dy;

		/* line buffers (we want them to be as compact as possible): */
		int ibuf = 0;                           /* circular buffer index */
		unsigned char * buf[3];                 /* actual pointers  */ /* Flawfinder: ignore */
		buf[0] = linebuf;
		buf[1] = linebuf + src_dx * BPP4;
		buf[2] = linebuf + 2 * src_dx * BPP4;

		/* get pointers: */
		sy1 = src_ptr + (src_x + src_y * src_pitch);        /* luma offset */
		sy2 = sy1 + src_pitch;
		su  = src_ptr + src_height * src_pitch + (src_x/2 + src_y/2 * src_pitch);
		sv  = su + src_height * src_pitch / 4;
		d1  = dest_ptr + dest_x * bpp[ccidx] + dest_y * dest_pitch; /* RGB offset */
		d2  = d1 + dest_pitch;

		/* check if we have misaligned top line: */
		if (src_y & 1) {

			/* convert an odd first line: */
			(*cvt) (buf[ibuf], buf[ibuf], 0, sy1, sy1, su, sv, src_x, src_dx);
			sy1 += src_pitch;   sy2 += src_pitch;
			su  += src_pitch/2; sv  += src_pitch/2;
			dy --;

		} else {

			/* otherwise, convert first two lines: */
			(*cvt) (buf[next[ibuf]], buf[next2[ibuf]], 0, sy1, sy2, su, sv, src_x, src_dx);
			sy1 += src_pitch*2; sy2 += src_pitch*2;
			su  += src_pitch/2; sv  += src_pitch/2;
			ibuf = next[ibuf];      /* skip first interpolation: */

			(*x2) (d1, d2, dest_x, buf[ibuf], buf[next[ibuf]], 0, src_dx);
			d1  += dest_pitch*2; d2  += dest_pitch*2;
			ibuf = next[ibuf];
			dy -= 2;
		}

		/*
		* Convert & interpolate the main portion of image:
		*
		*  source:      temp.store:                destination:
		*
		*               buf[ibuf] -------'    /--> d1
		*                                  x2  --> d2
		*  s1 --'   /-> buf[next[ibuf]] -<    /--> d1'=d1+2*pitch
		*        cvt                       x2 ---> d2'=d2+2*pitch
		*  s2 --/   '-> buf[next2[ibuf]] /
		*/
		while (dy >= 2) {

			/* convert two lines into XRGB buffers: */
			(*cvt) (buf[next[ibuf]], buf[next2[ibuf]], 0, sy1, sy2, su, sv, src_x, src_dx);
			sy1 += src_pitch*2; sy2 += src_pitch*2;
			su  += src_pitch/2; sv  += src_pitch/2;

			/* interpolate first line: */
			(*x2) (d1, d2, dest_x, buf[ibuf], buf[next[ibuf]], 0, src_dx);
			d1  += dest_pitch*2; d2  += dest_pitch*2;
			ibuf = next[ibuf];

			/* interpolate second one: */
			(*x2) (d1, d2, dest_x, buf[ibuf], buf[next[ibuf]], 0, src_dx);
			d1  += dest_pitch*2; d2  += dest_pitch*2;
			ibuf = next[ibuf];
			dy -= 2;
		}

		/* check the # of remaining rows: */
		if (dy & 1) {

			/* convert the last odd line: */
			(*cvt) (buf[next[ibuf]], buf[next[ibuf]], 0, sy1, sy1, su, sv, src_x, src_dx);

			/* interpolate first line: */
			(*x2) (d1, d2, dest_x, buf[ibuf], buf[next[ibuf]], 0, src_dx);
			d1  += dest_pitch*2; d2  += dest_pitch*2;
			ibuf = next[ibuf];

			/* replicate the last line: */
			(*x2) (d1, d2, dest_x, buf[ibuf], buf[ibuf], 0, src_dx);

		} else {

			/* replicate the last line: */
			(*x2) (d1, d2, dest_x, buf[ibuf], buf[ibuf], 0, src_dx);
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

/*
* I420->RGB* converters:
*/
int I420toRGB32 (unsigned char *dest_ptr, int dest_width, int dest_height,
				 int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				 unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				 int src_x, int src_y, int src_dx, int src_dy)
{
	return I420toRGB (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, 0);
}

int I420toRGB24 (unsigned char *dest_ptr, int dest_width, int dest_height,
				 int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				 unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				 int src_x, int src_y, int src_dx, int src_dy)
{
	return I420toRGB (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, 1);
}

int I420toRGB565 (unsigned char *dest_ptr, int dest_width, int dest_height,
				  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				  unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				  int src_x, int src_y, int src_dx, int src_dy)
{
	return I420toRGB (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, 2);
}

int I420toRGB555 (unsigned char *dest_ptr, int dest_width, int dest_height,
				  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				  unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				  int src_x, int src_y, int src_dx, int src_dy)
{
	return I420toRGB (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, 3);
}

int I420toRGB8 (unsigned char *dest_ptr, int dest_width, int dest_height,
				int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				int src_x, int src_y, int src_dx, int src_dy)
{
	return I420toRGB (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, 4);
}

int I420toBGR32 (unsigned char *dest_ptr, int dest_width, int dest_height,
				 int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				 unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				 int src_x, int src_y, int src_dx, int src_dy)
{
	return I420toRGB (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, 5);
}


/*
* "to I420" converters.
*
*/

int YV12toI420 (unsigned char *dest_ptr, int dest_width, int dest_height,
				int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* remove odd destination pixels: */
	if (!adjust_range (&dest_x, &dest_dx, &src_x, &src_dx, scale_x) ||
		!adjust_range (&dest_y, &dest_dy, &src_y, &src_dy, scale_y))
		return 0;

	/* check if we have matching chroma components: */
	if ((src_x & 1) || (src_y & 1))
		return -1;                          /* can't shift chromas */

	/* check if bottop-up images: */
	if (dest_pitch <= 0 || src_pitch <= 0)
		return -1;                          /* not supported */
	/*
	*  if (!is_dest_alpha && !is_dest_beta && !is_dest_gamma && !is_dest_kappa)
	*/
	{
		/* just move data in, no color adjustments: */
		unsigned char *s, *d;
		int src_uv_offs, dest_uv_offs;
		register int i;

		/* copy Y plane: */
		s = src_ptr + src_x + src_y * src_pitch;
		d = dest_ptr + dest_x + dest_y * dest_pitch;
		for (i = 0; i < dest_dy; i ++) {
			memcpy (d, s, dest_dx); /* Flawfinder: ignore */
			s += src_pitch;
			d += dest_pitch;
		}

		/* get Cr/Cb offsets: */
		src_uv_offs = src_height * src_pitch / 4;
		dest_uv_offs = dest_height * dest_pitch / 4;

		/* copy & flip Cr/Cb planes: */
		s = (src_ptr + src_height * src_pitch) + src_x/2 + src_y/2 * src_pitch/2;
		d = (dest_ptr + dest_height * dest_pitch) + dest_x/2 + dest_y/2 * dest_pitch/2;
		for (i = 0; i < dest_dy/2; i ++) {
			memcpy (d, s + src_uv_offs, dest_dx/2); /* Flawfinder: ignore */
			memcpy (d + dest_uv_offs, s, dest_dx/2); /* Flawfinder: ignore */
			s += src_pitch/2;
			d += dest_pitch/2;
		}
	}
	/*
	*  else {
	*      put all the color-dependent stuff here ...
	*  }
	*/
	return 0;
}

static void lineYVU9toI420 (unsigned char *d, unsigned char *s, int x, int dx)
{
	register int i;

	/* first pixel: */
	if (x & 2) {
		d[0] = s[0];
		s += 1;
		d += 1;
		dx -= 2;
	}
	/* the main loop: */
	for (i = 0; i < dx/4; i ++) {
		d[i*2] = s[i];
		d[i*2+1] = s[i];
	}
	/* last pixel: */
	if (dx & 2)
		d[dx/2] = s[dx/4];
}

int YVU9toI420 (unsigned char *dest_ptr, int dest_width, int dest_height,
				int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* remove odd destination pixels: */
	if (!adjust_range (&dest_x, &dest_dx, &src_x, &src_dx, scale_x) ||
		!adjust_range (&dest_y, &dest_dy, &src_y, &src_dy, scale_y))
		return 0;

	/* check if we have matching chroma components: */
	if ((src_x & 1) || (src_y & 1))
		return -1;                          /* can't shift chromas */

	/* check if bottop-up images: */
	if (dest_pitch <= 0 || src_pitch <= 0)
		return -1;                          /* not supported */
	/*
	*  if (!is_dest_alpha && !is_dest_beta && !is_dest_gamma && !is_dest_kappa)
	*/
	{
		/* no color adjustments: */
		unsigned char *s, *d;
		int src_uv_offs, dest_uv_offs;
		register int j;

		/* copy Y plane: */
		s = src_ptr + src_x + src_y * src_pitch;
		d = dest_ptr + dest_x + dest_y * dest_pitch;
		for (j = 0; j < dest_dy; j ++) {
			memcpy (d, s, dest_dx); /* Flawfinder: ignore */
			s += src_pitch;
			d += dest_pitch;
		}

		/* get Cr/Cb offsets: */
		src_uv_offs = src_height * src_pitch / 16;
		dest_uv_offs = dest_height * dest_pitch / 4;

		/* get pointers: */
		s = (src_ptr + src_height * src_pitch) + src_x/4 + src_y/4 * src_pitch/4;
		d = (dest_ptr + dest_height * dest_pitch) + dest_x/2 + dest_y/2 * dest_pitch/2;

		/* top lines: */
		if (src_y & 2) {
			lineYVU9toI420 (d, s, src_x, dest_dx);   /* Cr */
			lineYVU9toI420 (d + dest_uv_offs, s + src_uv_offs, src_x, dest_dx);  /* Cb */
			s += src_pitch/4;
			d += dest_pitch/2;
			dest_dy -= 2;
		}
		/* the main loop (processes two lines a time): */
		for (j = 0; j < dest_dy/4; j ++) {
			lineYVU9toI420 (d, s, src_x, dest_dx);   /* Cr */
			memcpy (d + dest_pitch/2, d, dest_dx/2); /* Flawfinder: ignore */
			lineYVU9toI420 (d + dest_uv_offs, s + src_uv_offs, src_x, dest_dx);  /* Cb */
			memcpy (d + dest_pitch/2 + dest_uv_offs, d + dest_uv_offs, dest_dx/2); /* Flawfinder: ignore */
			s += src_pitch/4;
			d += dest_pitch;
		}
		/* bottom lines: */
		if (dest_dy & 2) {
			lineYVU9toI420 (d, s, src_x, dest_dx);   /* Cr */
			lineYVU9toI420 (d + dest_uv_offs, s + src_uv_offs, src_x, dest_dx);  /* Cb */
		}
	}
	/*
	*  else {
	*      put all the color-dependent stuff here ...
	*  }
	*/
	return 0;
}

int YUY2toI420 (unsigned char *dest_ptr, int dest_width, int dest_height,
				int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* remove odd destination pixels: */
	if (!adjust_range (&dest_x, &dest_dx, &src_x, &src_dx, scale_x) ||
		!adjust_range (&dest_y, &dest_dy, &src_y, &src_dy, scale_y))
		return 0;

	/* check if we have misaligned source: */
	if (src_x & 1)
		return -1;                          /* can't shift chromas */

	/* check if bottop-up images: */
	if (dest_pitch <= 0) return -1;     /* not supported */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;

	/*
	*  if (!is_dest_alpha && !is_dest_beta && !is_dest_gamma && !is_dest_kappa)
	*/
	{
		/* just move data in, no color adjustments: */
		unsigned char *s1, *s2, *d1, *d2, *dv, *du;
		register int i, j;

		/* get pointers: */
		s1 = src_ptr + src_x * 2 + src_y * src_pitch;    /* 2 bytes/pixel */
		s2 = s1 + src_pitch * 2;
		d1 = dest_ptr + dest_x + dest_y * dest_pitch;   /* luma offsets  */
		d2 = d1 + dest_pitch;
		du = dest_ptr + dest_height * dest_pitch + (dest_x/2 + dest_y/2 * dest_pitch/2);
		dv = du + dest_height * dest_pitch/4;

		/* the main loop (processes lines a time): */
		for (i = 0; i < dest_dy/2; i ++) {

			/* copy 2x2 pixels: */
			for (j = 0; j < dest_dx/2; j ++) {

				/* copy luma components: */
				d1[j*2]   = s1[j*4];
				d1[j*2+1] = s1[j*4+2];
				d2[j*2]   = s2[j*4];
				d2[j*2+1] = s2[j*4+2];

				/* average chromas: */
				du[j] = (s1[j*4+1] + s2[j*4+1]) / 2;
				dv[j] = (s1[j*4+3] + s2[j*4+3]) / 2;
			}

			s1 += src_pitch*2;  s2 += src_pitch*2;
			d1 += dest_pitch*2; d2 += dest_pitch*2;
			du += dest_pitch/2; dv += dest_pitch/2;
		}
	}
	/*
	*  else {
	*      put all the color-dependent stuff here ...
	*  }
	*/
	return 0;
}

int UYVYtoI420 (unsigned char *dest_ptr, int dest_width, int dest_height,
				int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* remove odd destination pixels: */
	if (!adjust_range (&dest_x, &dest_dx, &src_x, &src_dx, scale_x) ||
		!adjust_range (&dest_y, &dest_dy, &src_y, &src_dy, scale_y))
		return 0;

	/* check if we have misaligned source: */
	if (src_x & 1)
		return -1;                          /* can't shift chromas */

	/* check if bottop-up images: */
	if (dest_pitch <= 0) return -1;     /* not supported */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;

	/*
	*  if (!is_dest_alpha && !is_dest_beta && !is_dest_gamma && !is_dest_kappa)
	*/
	{
		/* just move data in, no color adjustments: */
		unsigned char *s1, *s2, *d1, *d2, *dv, *du;
		register int i, j;

		/* get pointers: */
		s1 = src_ptr + src_x * 2 + src_y * src_pitch;    /* 2 bytes/pixel */
		s2 = s1 + src_pitch * 2;
		d1 = dest_ptr + dest_x + dest_y * dest_pitch;   /* luma offsets  */
		d2 = d1 + dest_pitch;
		du = dest_ptr + dest_height * dest_pitch + (dest_x/2 + dest_y/2 * dest_pitch/2);
		dv = du + dest_height * dest_pitch/4;

		/* the main loop (processes lines a time): */
		for (i = 0; i < dest_dy/2; i ++) {

			/* copy 2x2 pixels: */
			for (j = 0; j < dest_dx/2; j ++) {

				/* copy luma components: */
				d1[j*2]   = s1[j*4+1];
				d1[j*2+1] = s1[j*4+3];
				d2[j*2]   = s2[j*4+1];
				d2[j*2+1] = s2[j*4+3];

				/* average chromas: */
				du[j] = (s1[j*4]   + s2[j*4])   / 2;
				dv[j] = (s1[j*4+2] + s2[j*4+2]) / 2;
			}

			s1 += src_pitch*2;  s2 += src_pitch*2;
			d1 += dest_pitch*2; d2 += dest_pitch*2;
			du += dest_pitch/2; dv += dest_pitch/2;
		}
	}
	/*
	*  else {
	*      put all the color-dependent stuff here ...
	*  }
	*/
	return 0;
}

int RGB32toI420 (unsigned char *dest_ptr, int dest_width, int dest_height,
				 int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				 unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				 int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}

int RGB24toI420 (unsigned char *dest_ptr, int dest_width, int dest_height,
				 int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				 unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				 int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* align destination rectangle: */
	if (!adjust_range (&dest_x, &dest_dx, &src_x, &src_dx, scale_x) ||
		!adjust_range (&dest_y, &dest_dy, &src_y, &src_dy, scale_y))
		return 0;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch <= 0) return -1;     /* not supported */

	/*
	*  if (!is_dest_alpha && !is_dest_beta && !is_dest_gamma && !is_dest_kappa)
	*/
	{
		/* just move data in, no color adjustments: */
		unsigned char *s1, *s2, *d1, *d2, *dv, *du;
		register int i, j;

		/* get pointers: */
		s1 = src_ptr + src_x * BPP3 + src_y * src_pitch; /* 3 bytes/pixel */
		s2 = s1 + src_pitch;
		d1 = dest_ptr + dest_x + dest_y * dest_pitch;    /* luma offsets  */
		d2 = d1 + dest_pitch;
		du = dest_ptr + dest_height * dest_pitch + (dest_x/2 + dest_y/2 * dest_pitch/2); /* chroma offset */
		dv = du + dest_height * dest_pitch/4;

		/* the main loop (processes 2 lines a time): */
		for (i = 0; i < dest_dy/2; i ++) {

			/* convert 2x2 block: */
			for (j = 0; j < dest_dx/2; j ++) {

				int r4, b4, y4;

				/* process lumas: */
				{
					register unsigned int r, b, y;

					r4 = (r = s1[2]);       /* BGR */
					b4 = (b = s1[0]);
					y4 = (y = yrtab [r] + ygtab [s1[1]] + ybtab [b]);
					d1[0] = yytab [y];

					r4 += (r = s1[5]);      /* bgrBGR */
					b4 += (b = s1[3]);
					y4 += (y = yrtab [r] + ygtab [s1[4]] + ybtab [b]);
					d1[1] = yytab [y];

					r4 += (r = s2[2]);      /* BGR */
					b4 += (b = s2[0]);
					y4 += (y = yrtab [r] + ygtab [s2[1]] + ybtab [b]);
					d2[0] = yytab [y];

					r4 += (r = s2[5]);      /* bgrBGR */
					b4 += (b = s2[3]);
					y4 += (y = yrtab [r] + ygtab [s2[4]] + ybtab [b]);
					d2[1] = yytab [y];
				}

				/* average chromas: */
				dv[0] = vrytab [VMIN+(r4-y4)/4];
				du[0] = ubytab [UMIN+(b4-y4)/4];

				/* go to the next block: */
				s1 += 2 * BPP3; s2 += 2 * BPP3;
				d1 += 2; d2 += 2;
				du += 1; dv += 1;
			}

			/* switch to the next two lines: */
			s1 += src_pitch * 2 - dest_dx * BPP3;
			s2 += src_pitch * 2 - dest_dx * BPP3;
			d1 += dest_pitch * 2 - dest_dx;
			d2 += dest_pitch * 2 - dest_dx;
			du += (dest_pitch - dest_dx)/2;
			dv += (dest_pitch - dest_dx)/2;
		}
	}
	/*
	*  else {
	*      put all the color-dependent stuff here ...
	*  }
	*/
	return 0;
}

int RGB565toI420 (unsigned char *dest_ptr, int dest_width, int dest_height,
				  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				  unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				  int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}

int RGB555toI420 (unsigned char *dest_ptr, int dest_width, int dest_height,
				  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				  unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				  int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}

int RGB8toI420 (unsigned char *dest_ptr, int dest_width, int dest_height,
				int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}


/*
* "RGBx to BGR32" converters.
*
*/

int RGB32toBGR32 (unsigned char *dest_ptr, int dest_width, int dest_height,
				  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				  unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				  int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP4 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP4 + dest_y * dest_pitch;

		/* convert image: */
		for (i = 0; i < dest_dy; i ++) {

			/* convert a line: */
			register int ddx = dest_dx;
			while (ddx) {
				register unsigned int a;
				a = *(unsigned int *)s;     /* 0x00RRGGBB */
				*(unsigned int *)d =
					((a & 0x000000ff) << 16) |
					((a & 0x0000ff00) << 0)  |
					((a & 0x00ff0000) >> 16);
				s += BPP4;
				d += BPP4;
				ddx --;
			}
			s += src_pitch - dest_dx * BPP4;
			d += dest_pitch - dest_dx * BPP4;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP4 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP4 + dest_y * dest_pitch;

		/* convert & stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* convert & stretch a line: */
			register int sdx = src_dx;
			while (sdx) {
				register unsigned int a, c;
				a = *(unsigned int *)s;
				c = ((a & 0x000000ff) << 16) |
					((a & 0x0000ff00) << 0)  |
					((a & 0x00ff0000) >> 16);
				*(unsigned int *)d = c;
				*(unsigned int *)(d+BPP4) = c;
				d += 2*BPP4; s += BPP4;
				sdx --;
			}
			s -= src_dx * BPP4;
			d -= src_dx * 2*BPP4;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP4); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

int RGB24toBGR32 (unsigned char *dest_ptr, int dest_width, int dest_height,
				  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				  unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				  int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP3 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP4 + dest_y * dest_pitch;

		/* convert image: */
		for (i = 0; i < dest_dy; i ++) {

			/* convert a line: */
			register int ddx = dest_dx;
			while (ddx) {
				/* RGB -> 0BGR: */
				*(unsigned int *)d = (unsigned int)
					(s[0] << 16) | (s[1] << 8) | s[2];
				d += BPP4; s += BPP3;
				ddx --;
			}
			s += src_pitch - dest_dx * BPP3;
			d += dest_pitch - dest_dx * BPP4;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP3 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP4 + dest_y * dest_pitch;

		/* convert & stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* convert & stretch a line: */
			register int sdx = src_dx;
			while (sdx) {
				/* RGB -> 0BGR: */
				register unsigned int a;
				a = (unsigned int)
					(s[0] << 16) | (s[1] << 8) | s[2];
				*(unsigned int *)d = a;
				*(unsigned int *)(d+BPP4) = a;
				d += 2*BPP4; s += BPP3;
				sdx --;
			}
			s -= src_dx * BPP3;
			d -= src_dx * 2*BPP4;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP4); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

int RGB565toBGR32 (unsigned char *dest_ptr, int dest_width, int dest_height,
				   int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				   unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				   int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP2 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP4 + dest_y * dest_pitch;

		/* convert image: */
		for (i = 0; i < dest_dy; i ++) {

			/* convert a line: */
			register int ddx = dest_dx;
			while (ddx) {
				/* rrrr,rggg,gggb,bbbb -> 0BGR: */
				register unsigned short a;
				a = *(unsigned short *)s;
				*(unsigned int *)d = (unsigned int)
					((a & 0x001F) << 19)|
					((a & 0x07E0) << 5) |
					((a & 0xF800) >> 8);
				d += BPP4; s += BPP2;
				ddx --;
			}
			s += src_pitch - dest_dx * BPP2;
			d += dest_pitch - dest_dx * BPP4;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP2 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP4 + dest_y * dest_pitch;

		/* convert & stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* convert & stretch a line: */
			register int sdx = src_dx;
			while (sdx) {
				register unsigned short a;
				register unsigned int c;
				a = *(unsigned short *)s;
				c = ((a & 0x001F) << 19)|
					((a & 0x07E0) << 5) |
					((a & 0xF800) >> 8);
				*(unsigned int *)d = c;
				*(unsigned int *)(d+BPP4) = c;
				d += 2*BPP4; s += BPP2;
				sdx --;
			}
			s -= src_dx * BPP2;
			d -= src_dx * 2*BPP4;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP4); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

int RGB555toBGR32 (unsigned char *dest_ptr, int dest_width, int dest_height,
				   int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				   unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				   int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP2 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP4 + dest_y * dest_pitch;

		/* convert image: */
		for (i = 0; i < dest_dy; i ++) {

			/* convert a line: */
			register int ddx = dest_dx;
			while (ddx) {
				/* 0rrrr,rgg,gggb,bbbb -> 0BGR: */
				register unsigned short a;
				a = *(unsigned short *)s;
				*(unsigned int *)d = (unsigned int)
					((a & 0x001F) << 19)|
					((a & 0x03E0) << 6) |
					((a & 0x7C00) >> 7);
				d += BPP4; s += BPP2;
				ddx --;
			}
			s += src_pitch - dest_dx * BPP2;
			d += dest_pitch - dest_dx * BPP4;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP2 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP4 + dest_y * dest_pitch;

		/* convert & stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* convert & stretch a line: */
			register int sdx = src_dx;
			while (sdx) {
				register unsigned short a;
				register unsigned int c;
				a = *(unsigned short *)s;
				c = ((a & 0x001F) << 19)|
					((a & 0x03E0) << 6) |
					((a & 0x7C00) >> 7);
				*(unsigned int *)d = c;
				*(unsigned int *)(d+BPP4) = c;
				d += 2*BPP4; s += BPP2;
				sdx --;
			}
			s -= src_dx * BPP2;
			d -= src_dx * 2*BPP4;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP4); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

int RGB8toBGR32 (unsigned char *dest_ptr, int dest_width, int dest_height,
				 int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				 unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				 int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}


/********************************
*
* "RGBx to RGBy" converters.
*
********************************/

/*
* RGB32toRGB32() converter:
*  1:1, 2:1
*/
int RGB32toRGB32 (unsigned char *dest_ptr, int dest_width, int dest_height,
				  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				  unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				  int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP4 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP4 + dest_y * dest_pitch;

		/* copy image: */
		for (i = 0; i < dest_dy; i ++) {
			memcpy (d, s, dest_dx * BPP4);  /* copy dest_dx pixels */ /* Flawfinder: ignore */
			s += src_pitch;
			d += dest_pitch;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP4 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP4 + dest_y * dest_pitch;

		/* stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* stretch a line: */
			register int sdx = src_dx;
			while (sdx) {
				register unsigned int a;
				a = *(unsigned int *)s;
				*(unsigned int *)d = a;
				*(unsigned int *)(d+BPP4) = a;
				d += 2*BPP4; s += BPP4;
				sdx --;
			}
			s -= src_dx * BPP4;
			d -= src_dx * 2*BPP4;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP4); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

int RGB32toRGB24 (unsigned char *dest_ptr, int dest_width, int dest_height,
				  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				  unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				  int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}

int RGB32toRGB565 (unsigned char *dest_ptr, int dest_width, int dest_height,
				   int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				   unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				   int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}

int RGB32toRGB555 (unsigned char *dest_ptr, int dest_width, int dest_height,
				   int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				   unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				   int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}

/*
* No dithering yet.
*/
int RGB32toRGB8 (unsigned char *dest_ptr, int dest_width, int dest_height,
				 int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				 unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				 int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP4 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP1 + dest_y * dest_pitch;

		/* copy rows: */
		for (i = 0; i < dest_dy; i ++) {

			/* convert a line: */
			register int ddx = dest_dx;
			while (ddx) {
				register unsigned int a;
				a = *(unsigned int *)s;             /* BGR0 */
				*d = pmap[
					((a & 0x000000f0) >>  4) |
						((a & 0x0000f000) >>  8) |
						((a & 0x00f00000) >> 12)];
					d += BPP1; s += BPP4;
					ddx --;
			}

			/* bump pointers to the next row: */
			s += src_pitch - dest_dx * BPP4;
			d += dest_pitch - dest_dx * BPP1;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP4 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP1 + dest_y * dest_pitch;

		/* stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* stretch a line: */
			register int sdx = src_dx;
			while (sdx) {
				register unsigned int a;
				register unsigned char c;
				a = *(unsigned int *)s;             /* BRG0 */
				c = pmap[
					((a & 0x000000f0) >>  4) |
						((a & 0x0000f000) >>  8) |
						((a & 0x00f00000) >> 12)];
					*(d+0) = c;
					*(d+BPP1) = c;
					d += 2*BPP1; s += BPP4;
					sdx --;
			}
			s -= src_dx * BPP4;
			d -= src_dx * 2*BPP1;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP1); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

/*
* RGB24toRGB32() converter:
*  1:1, 2:1
*/
int RGB24toRGB32 (unsigned char *dest_ptr, int dest_width, int dest_height,
				  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				  unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				  int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP3 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP4 + dest_y * dest_pitch;

		/* copy rows: */
		for (i = 0; i < dest_dy; i ++) {

			register int sx = src_x, ddx = dest_dx;

			/* process misaligned pixels first: */
			while ((sx & 3) && ddx) {
				/* BGR -> BGR0: */
				*(unsigned int *)d = (unsigned int)s[0] | (s[1] << 8) | (s[2] << 16);
				d += BPP4; s += BPP3;
				sx ++; ddx --;
			}

			/* main loop: process 4 pixels a time: */
			while (ddx >= 4) {
				register unsigned int a, b;
				a = *(unsigned int *)s;             /* BGR.B */
				b = *(unsigned int *)(s+4);         /* GR.BG */
				*(unsigned int *)d      = a & 0x00FFFFFF;
				*(unsigned int *)(d+4)  = ((a >> 24) | (b << 8)) & 0x00FFFFFF;
				a = *(unsigned int *)(s+8);         /* R.BGR */
				*(unsigned int *)(d+8)  = ((b >> 16) | (a << 16)) & 0x00FFFFFF;
				*(unsigned int *)(d+12) = a >> 8;
				d += BPP4*4; s += BPP3*4;
				ddx -= 4;
			}

			/* process the remaining 1..3 pixels: */
			while (ddx) {
				/* RGB -> RGB0: */
				*(unsigned int *)d = (unsigned int)s[0] | (s[1] << 8) | (s[2] << 16);
				d += BPP4; s += BPP3;
				ddx --;
			}

			/* bump pointers to the next row: */
			s += src_pitch - dest_dx * BPP3;
			d += dest_pitch - dest_dx * BPP4;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP3 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP4 + dest_y * dest_pitch;

		/* stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* stretch a line: */
			register int sx = src_x, sdx = src_dx;

			/* misaligned pixels first: */
			while ((sx & 3) && sdx) {
				/* BGR -> BGR0: */
				register unsigned int a;
				a = (unsigned int)s[0] | (s[1] << 8) | (s[2] << 16);
				*(unsigned int *)d = a;
				*(unsigned int *)(d+BPP4) = a;
				d += 2*BPP4; s += BPP3;
				sx ++; sdx --;
			}
			/* main bulk of data: */
			while (sdx >= 4) {
				register unsigned int a, b, c;
				a = *(unsigned int *)s;             /* bgrB */
				b = *(unsigned int *)(s+4);         /* GRbg */
				c = a & 0x00FFFFFF;
				*(unsigned int *)(d) = c;
				*(unsigned int *)(d+BPP4) = c;
				c = ((a >> 24) | (b << 8)) & 0x00FFFFFF;
				*(unsigned int *)(d+2*BPP4) = c;
				*(unsigned int *)(d+3*BPP4) = c;
				a = *(unsigned int *)(s+8);         /* rBGR */
				c = ((b >> 16) | (a << 16)) & 0x00FFFFFF;
				*(unsigned int *)(d+4*BPP4) = c;
				*(unsigned int *)(d+5*BPP4) = c;
				c = a >> 8;
				*(unsigned int *)(d+6*BPP4) = c;
				*(unsigned int *)(d+7*BPP4) = c;
				d += 4*2*BPP4; s += 4*BPP3;
				sdx -= 4;
			}
			/* the remaining 1..3 pixels: */
			while (sdx) {
				/* BGR -> BGR0: */
				register unsigned int a;
				a = (unsigned int)s[0] | (s[1] << 8) | (s[2] << 16);
				*(unsigned int *)d = a;
				*(unsigned int *)(d+BPP4) = a;
				d += 2*BPP4; s += BPP3;
				sdx --;
			}
			s -= src_dx * BPP3;
			d -= src_dx * 2*BPP4;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP4); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

/*
* RGB24toRGB24() converter:
*  1:1, 2:1
*/
int RGB24toRGB24 (unsigned char *dest_ptr, int dest_width, int dest_height,
				  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				  unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				  int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP3 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP3 + dest_y * dest_pitch;

		/* copy image: */
		for (i = 0; i < dest_dy; i ++) {
			memcpy (d, s, dest_dx * BPP3);  /* copy dest_dx pixels */ /* Flawfinder: ignore */
			s += src_pitch;
			d += dest_pitch;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP3 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP3 + dest_y * dest_pitch;

		/* stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* stretch a line: */
			register int sx = src_x, sdx = src_dx;

			/* misaligned pixels first: */
			while ((sx & 3) && sdx) {
				register unsigned char a;
				a = *s; *d = a; *(d+BPP3) = a;
				a = *(s+1); *(d+1) = a; *(d+1+BPP3) = a;
				a = *(s+2); *(d+2) = a; *(d+2+BPP3) = a;
				d += 2*BPP3; s += BPP3;
				sx ++; sdx --;
			}
			/* main bulk of data: */
			while (sdx >= 4) {
				register unsigned int a, b;
				a = *(unsigned int *)s;             /* bgrB */
				b = *(unsigned int *)(s+4);         /* GRbg */
				*(unsigned int *)(d) = (a & 0x00FFFFFF) | (a << 24);    /* bgrb */
				*(unsigned int *)(d+4) = (a >> 8) | (b << 24);          /* grBG */
				*(unsigned int *)(d+2*4) = ((b & 0xFF00) >> 8) |        /* RBGR */
					((a & 0xFF000000) >> 16) | (b << 16);
				a = *(unsigned int *)(s+8);         /* rBGR */
				*(unsigned int *)(d+3*4) = (b >> 16) |                  /* bgrb */
					((a & 0xFF) << 16) | ((b & 0xFF0000) << 8);
				*(unsigned int *)(d+4*4) = (b >> 24) | (a << 8);        /* grBG */
				*(unsigned int *)(d+5*4) = (a >> 24) | (a & 0xFFFFFF00);/* RBGR */
				d += 4*2*BPP3; s += 4*BPP3;
				sdx -= 4;
			}
			/* the remaining 1..3 pixels: */
			while (sdx) {
				register unsigned char a;
				a = *s; *d = a; *(d+BPP3) = a;
				a = *(s+1); *(d+1) = a; *(d+1+BPP3) = a;
				a = *(s+2); *(d+2) = a; *(d+2+BPP3) = a;
				d += 2*BPP3; s += BPP3;
				sdx --;
			}
			s -= src_dx * BPP3;
			d -= src_dx * 2*BPP3;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP3); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

/*
* RGB24toRGB565() converter:
*  1:1, 2:1
*/
int RGB24toRGB565 (unsigned char *dest_ptr, int dest_width, int dest_height,
				   int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				   unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				   int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1)
	{

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP3 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP2 + dest_y * dest_pitch;

		/* copy rows: */
		for (i = 0; i < dest_dy; i ++) {

			register int sx = src_x, ddx = dest_dx;

			/* process misaligned pixels first: */
			while ((sx & 3) && ddx) {
				/* bbbbbbbb.gggggggg.rrrrrrrr -> gggbbbbb.rrrrrggg: */
				*(unsigned short *)d =
					(s[0] >> 3) | ((s[1] & 0xFC) << 3) | ((s[2] & 0xF8) << 8);
				d += BPP2;  s += BPP3;
				sx ++; ddx --;
			}

			/* main loop: process 4 pixels a time: */
			while (ddx >= 4) {

				register unsigned int a, b;

				a = *(unsigned int *)s;             /* BGR.B */
				b = *(unsigned int *)(s+4);         /* GR.BG */
				*(unsigned int *)d =
					((a & 0xF8) >> 3) | ((a & 0xFC00) >> 5) | ((a & 0xF80000) >> 8) |
					((a & 0xF8000000) >> 11) | ((b & 0xFC) << 19) | ((b & 0xF800) << 16);
				a = *(unsigned int *)(s+8);         /* R.BGR */
				*(unsigned int *)(d+4) =
					((b & 0xF80000) >> 19) | ((b & 0xFC000000) >> 21) | ((a & 0xF8) << 8) |
					((a & 0xF800) << 5) | ((a & 0xFC0000) << 3) | (a & 0xF8000000);

				d += BPP2*4; s += BPP3*4; ddx -= 4;
			}

			/* process the remaining 1..3 pixels: */
			while (ddx) {
				/* bbbbbbbb.gggggggg.rrrrrrrr -> gggbbbbb.rrrrrggg: */
				*(unsigned short *)d =
					(s[0] >> 3) | ((s[1] & 0xFC) << 3) | ((s[2] & 0xF8) << 8);
				d += BPP2;  s += BPP3;
				ddx --;
			}

			/* bump pointers to the next row: */
			s += src_pitch - dest_dx * BPP3;
			d += dest_pitch - dest_dx * BPP2;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP3 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP2 + dest_y * dest_pitch;

		/* stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* stretch a line: */
			register int sx = src_x, sdx = src_dx;

			/* misaligned pixels first: */
			while ((sx & 3) && sdx) {
				/* bbbbbbbb.gggggggg.rrrrrrrr -> gggbbbbb.0rrrrrgg: */
				register unsigned short a;
				a = (s[0] >> 3) | ((s[1] & 0xFC) << 3) | ((s[2] & 0xF8) << 8);
				*(unsigned short *)d = a;
				*(unsigned short *)(d+BPP2) = a;
				d += 2*BPP2;  s += BPP3;
				sx ++; sdx --;
			}

			/* main bulk of data: */
			while (sdx >= 4) {
				register unsigned int a, b, c;
				a = *(unsigned int *)s;             /* bgrB */
				b = *(unsigned int *)(s+4);         /* GRbg */
				c = ((a & 0xF8) >> 3) | ((a & 0xFC00) >> 5) | ((a & 0xF80000) >> 8);
				*(unsigned int *)d = c | (c << 16);
				c = ((a & 0xF8000000) >> 11) | ((b & 0xFC) << 19) | ((b & 0xF800) << 16);
				*(unsigned int *)(d+2*BPP2) = c | (c >> 16);
				a = *(unsigned int *)(s+8);         /* rBGR */
				c = ((b & 0xF80000) >> 19) | ((b & 0xFC000000) >> 21) | ((a & 0xF8) << 8);
				*(unsigned int *)(d+2*2*BPP2) = c | (c << 16);
				c = ((a & 0xF800) << 5) | ((a & 0xFC0000) << 3) | (a & 0xF8000000);
				*(unsigned int *)(d+3*2*BPP2) = c | (c >> 16);
				d += 2*4*BPP2; s += 4*BPP3;
				sdx -= 4;
			}

			/* the remaining pixels: */
			while (sdx) {
				/* bbbbbbbb.gggggggg.rrrrrrrr -> gggbbbbb.0rrrrrgg: */
				register unsigned short a;
				a = (s[0] >> 3) | ((s[1] & 0xFC) << 3) | ((s[2] & 0xF8) << 8);
				*(unsigned short *)d = a;
				*(unsigned short *)(d+BPP2) = a;
				d += 2*BPP2;  s += BPP3;
				sdx --;
			}
			s -= src_dx * BPP3;
			d -= src_dx * 2*BPP2;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP2); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

/*
* RGB24toRGB555() converter:
*  1:1, 2:1
*/
int RGB24toRGB555 (unsigned char *dest_ptr, int dest_width, int dest_height,
				   int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				   unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				   int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP3 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP2 + dest_y * dest_pitch;

		/* copy rows: */
		for (i = 0; i < dest_dy; i ++) {

			register int sx = src_x, ddx = dest_dx;

			/* process misaligned pixels first: */
			while ((sx & 3) && ddx) {
				/* bbbbbbbb.gggggggg.rrrrrrrr -> gggbbbbb.0rrrrrgg: */
				*(unsigned short *)d =
					(s[0] >> 3) | ((s[1] & 0xF8) << 2) | ((s[2] & 0xF8) << 7);
				d += BPP2;  s += BPP3;
				sx ++; ddx --;
			}

			/* main loop: process 4 pixels a time: */
			while (ddx >= 4) {
				register unsigned int a, b;
				a = *(unsigned int *)s;             /* bgrB */
				b = *(unsigned int *)(s+4);         /* GRbg */
				*(unsigned int *)d =
					((a & 0xF8) >> 3) | ((a & 0xF800) >> 6) | ((a & 0xF80000) >> 9) |
					((a & 0xF8000000) >> 11) | ((b & 0xF8) << 18) | ((b & 0xF800) << 15);
				a = *(unsigned int *)(s+8);         /* rBGR */
				*(unsigned int *)(d+4) =
					((b & 0xF80000) >> 19) | ((b & 0xF8000000) >> 22) | ((a & 0xF8) << 7) |
					((a & 0xF800) << 5) | ((a & 0xF80000) << 2) | ((a & 0xF8000000) >> 1);
				d += BPP2*4; s += BPP3*4; ddx -= 4;
			}

			/* process the remaining 1..3 pixels: */
			while (ddx) {
				/* bbbbbbbb.gggggggg.rrrrrrrr -> gggbbbbb.rrrrrggg: */
				*(unsigned short *)d =
					(s[0] >> 3) | ((s[1] & 0xF8) << 2) | ((s[2] & 0xF8) << 7);
				d += BPP2;  s += BPP3;
				ddx --;
			}

			/* bump pointers to the next row: */
			s += src_pitch - dest_dx * BPP3;
			d += dest_pitch - dest_dx * BPP2;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP3 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP2 + dest_y * dest_pitch;

		/* stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* stretch a line: */
			register int sx = src_x, sdx = src_dx;

			/* misaligned pixels first: */
			while ((sx & 3) && sdx) {
				/* bbbbbbbb.gggggggg.rrrrrrrr -> gggbbbbb.0rrrrrgg: */
				register unsigned short a;
				a = (s[0] >> 3) | ((s[1] & 0xF8) << 2) | ((s[2] & 0xF8) << 7);
				*(unsigned short *)d = a;
				*(unsigned short *)(d+BPP2) = a;
				d += 2*BPP2;  s += BPP3;
				sx ++; sdx --;
			}

			/* main bulk of data: */
			while (sdx >= 4) {
				register unsigned int a, b, c;
				a = *(unsigned int *)s;             /* bgrB */
				b = *(unsigned int *)(s+4);         /* GRbg */
				c = ((a & 0xF8) >> 3) | ((a & 0xF800) >> 6) | ((a & 0xF80000) >> 9);
				*(unsigned int *)d = c | (c << 16);
				c = ((a & 0xF8000000) >> 11) | ((b & 0xF8) << 18) | ((b & 0xF800) << 15);
				*(unsigned int *)(d+2*BPP2) = c | (c >> 16);
				a = *(unsigned int *)(s+8);         /* rBGR */
				c = ((b & 0xF80000) >> 19) | ((b & 0xF8000000) >> 22) | ((a & 0xF8) << 7);
				*(unsigned int *)(d+2*2*BPP2) = c | (c << 16);
				c = ((a & 0xF800) << 5) | ((a & 0xF80000) << 2) | ((a & 0xF8000000) >> 1);
				*(unsigned int *)(d+3*2*BPP2) = c | (c >> 16);
				d += 2*4*BPP2; s += 4*BPP3;
				sdx -= 4;
			}

			/* the remaining pixels: */
			while (sdx) {
				/* bbbbbbbb.gggggggg.rrrrrrrr -> gggbbbbb.0rrrrrgg: */
				register unsigned short a;
				a = (s[0] >> 3) | ((s[1] & 0xF8) << 2) | ((s[2] & 0xF8) << 7);
				*(unsigned short *)d = a;
				*(unsigned short *)(d+BPP2) = a;
				d += 2*BPP2;  s += BPP3;
				sdx --;
			}
			s -= src_dx * BPP3;
			d -= src_dx * 2*BPP2;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP2); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

/*
* No dithering yet.
*/
int RGB24toRGB8 (unsigned char *dest_ptr, int dest_width, int dest_height,
				 int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				 unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				 int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP3 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP1 + dest_y * dest_pitch;

		/* copy rows: */
		for (i = 0; i < dest_dy; i ++) {

			register int sx = src_x, ddx = dest_dx;

			/* process misaligned pixels first: */
			while ((sx & 3) && ddx) {
				/* BGR -> palette index: */
				*d = pmap[(unsigned int)
					((s[0] & 0xf0) >> 4) |
					((s[1] & 0xf0)     ) |
					((s[2] & 0xf0) << 4)];
				d += BPP1; s += BPP3;
				sx ++; ddx --;
			}

			/* main loop: process 4 pixels a time: */
			while (ddx >= 4) {
				register unsigned int a, b;
				a = *(unsigned int *)s;             /* BGR.B */
				b = *(unsigned int *)(s+4);         /* GR.BG */
				*d = pmap[(unsigned int)
					((a & 0x000000f0) >>  4) |
					((a & 0x0000f000) >>  8) |
					((a & 0x00f00000) >> 12)];
				*(d+BPP1) = pmap[(unsigned int)
					((a & 0xf0000000) >> 28) |
					((b & 0x000000f0)      ) |
					((b & 0x0000f000) >>  4)];
				a = *(unsigned int *)(s+8);         /* R.BGR */
				*(d+2*BPP1) = pmap[(unsigned int)
					((b & 0x00f00000) >> 20) |
					((b & 0xf0000000) >> 24) |
					((a & 0x000000f0) <<  4)];
				*(d+3*BPP1) = pmap[(unsigned int)
					((a & 0x0000f000) >> 12) |
					((a & 0x00f00000) >> 16) |
					((a & 0xf0000000) >> 20)];
				d += BPP1*4; s += BPP3*4;
				ddx -= 4;
			}

			/* process the remaining 1..3 pixels: */
			while (ddx) {
				/* RGB -> palette index: */
				*d = pmap[(unsigned int)
					((s[0] & 0xf0) >> 4) |
					((s[1] & 0xf0)     ) |
					((s[2] & 0xf0) << 4)];
				d += BPP1; s += BPP3;
				ddx --;
			}

			/* bump pointers to the next row: */
			s += src_pitch - dest_dx * BPP3;
			d += dest_pitch - dest_dx * BPP1;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP3 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP1 + dest_y * dest_pitch;

		/* stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* stretch a line: */
			register int sx = src_x, sdx = src_dx;

			/* misaligned pixels first: */
			while ((sx & 3) && sdx) {
				/* BGR -> palette index: */
				register unsigned char c;
				c = pmap[(unsigned int)
					((s[0] & 0xf0) >> 4) |
					((s[1] & 0xf0)     ) |
					((s[2] & 0xf0) << 4)];
				*d = c;
				*(d+BPP1) = c;
				d += 2*BPP1; s += BPP3;
				sx ++; sdx --;
			}

			/* main bulk of data: */
			while (sdx >= 4) {
				register unsigned int a, b;
				register unsigned char c;
				a = *(unsigned int *)s;             /* bgrB */
				b = *(unsigned int *)(s+4);         /* GRbg */
				c = pmap[(unsigned int)
					((a & 0x000000f0) >>  4) |
					((a & 0x0000f000) >>  8) |
					((a & 0x00f00000) >> 12)];
				*(d+0) = c;
				*(d+BPP1) = c;
				c = pmap[(unsigned int)
					((a & 0xf0000000) >> 28) |
					((b & 0x000000f0)      ) |
					((b & 0x0000f000) >>  4)];
				*(d+2*BPP1) = c;
				*(d+3*BPP1) = c;
				a = *(unsigned int *)(s+8);         /* rBGR */
				c = pmap[(unsigned int)
					((b & 0x00f00000) >> 20) |
					((b & 0xf0000000) >> 24) |
					((a & 0x000000f0) <<  4)];
				*(d+4*BPP1) = c;
				*(d+5*BPP1) = c;
				c = pmap[(unsigned int)
					((a & 0x0000f000) >> 12) |
					((a & 0x00f00000) >> 16) |
					((a & 0xf0000000) >> 20)];
				*(d+6*BPP1) = c;
				*(d+7*BPP1) = c;
				d += 4*2*BPP1; s += 4*BPP3;
				sdx -= 4;
			}
			/* the remaining 1..3 pixels: */
			while (sdx) {
				/* BGR -> palette index: */
				register unsigned char c;
				c = pmap[(unsigned int)
					((s[0] & 0xf0) >> 4) |
					((s[1] & 0xf0)     ) |
					((s[2] & 0xf0) << 4)];
				*d = c;
				*(d+BPP1) = c;
				d += 2*BPP1; s += BPP3;
				sdx --;
			}
			s -= src_dx * BPP3;
			d -= src_dx * 2*BPP1;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP1); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

int RGB565toRGB32 (unsigned char *dest_ptr, int dest_width, int dest_height,
				   int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				   unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				   int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}

int RGB565toRGB24 (unsigned char *dest_ptr, int dest_width, int dest_height,
				   int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				   unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				   int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}

/*
* RGB565toRGB565() converter:
*  1:1, 2:1
*/
int RGB565toRGB565 (unsigned char *dest_ptr, int dest_width, int dest_height,
					int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
					unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
					int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP2 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP2 + dest_y * dest_pitch;

		/* copy image: */
		for (i = 0; i < dest_dy; i ++) {
			memcpy (d, s, dest_dx * BPP2);  /* copy dest_dx pixels */ /* Flawfinder: ignore */
			s += src_pitch;
			d += dest_pitch;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP2 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP2 + dest_y * dest_pitch;

		/* stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* stretch a line: */
			register int sdx = src_dx;

			/* misaligned pixel first: */
			if (src_x & 1) {
				register unsigned short a;
				a = *(unsigned short *)s;
				*(unsigned short *)d = a;
				*(unsigned short *)(d+BPP2) = a;
				d += 2*BPP2; s += BPP2;
				sdx --;
			}
			/* main bulk of data: */
			while (sdx >= 2) {
				register unsigned int a;
				a = *(unsigned int *)s;
				*(unsigned int *)d = (a & 0xFFFF) | (a << 16);
				*(unsigned int *)(d+2*BPP2) = (a & 0xFFFF0000) | (a >> 16);
				d += 2*2*BPP2; s += 2*BPP2;
				sdx -= 2;
			}
			/* the remaining odd pixel: */
			if (sdx) {
				register unsigned short a;
				a = *(unsigned short *)s;
				*(unsigned short *)d = a;
				*(unsigned short *)(d+BPP2) = a;
				d += 2*BPP2; s += BPP2;
			}
			s -= src_dx * BPP2;
			d -= src_dx * 2*BPP2;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP2); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

int RGB565toRGB555 (unsigned char *dest_ptr, int dest_width, int dest_height,
					int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
					unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
					int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}

/*
* No dithering yet.
*/
int RGB565toRGB8 (unsigned char *dest_ptr, int dest_width, int dest_height,
				  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				  unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				  int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP2 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP1 + dest_y * dest_pitch;

		/* copy rows: */
		for (i = 0; i < dest_dy; i ++) {

			register int ddx = dest_dx;

			/* first odd pixel: */
			if (src_x & 1) {
				/* gggbbbbb.rrrrrggg -> palette index: */
				unsigned short a = *(unsigned short *)s;
				*d = pmap[
					((a & 0x001E) >> 1) |
						((a & 0x0780) >> 3) |
						((a & 0xf000) >> 4)];
					d += BPP1; s += BPP2;
					ddx --;
			}

			/* main loop: process 2 pixels a time: */
			while (ddx >= 2) {
				/* gggbbbbb.rrrrrggg.gggbbbbb.rrrrrggg -> 2 palette indices */
				register unsigned int a;
				a = *(unsigned int *)s;
				*d = pmap[
					((a & 0x001e) >> 1) |
						((a & 0x0780) >> 3) |
						((a & 0xf000) >> 4)];
					*(d+BPP1) = pmap[
						((a & 0x001e0000) >> 17) |
							((a & 0x07800000) >> 19) |
							((a & 0xf0000000) >> 20)];
						d += BPP1*2; s += BPP2*2;
						ddx -= 2;
			}

			/* the remaining odd pixel: */
			if (ddx) {
				/* gggbbbbb.rrrrrggg -> palette index: */
				unsigned short a = *(unsigned short *)s;
				*d = pmap[
					((a & 0x001e) >> 1) |
						((a & 0x0780) >> 3) |
						((a & 0xf000) >> 4)];
					d += BPP1; s += BPP2;
					ddx --;
			}

			/* bump pointers to the next row: */
			s += src_pitch - dest_dx * BPP2;
			d += dest_pitch - dest_dx * BPP1;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP2 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP1 + dest_y * dest_pitch;

		/* stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* stretch a line: */
			register int sdx = src_dx;

			/* first odd pixel: */
			if (src_x & 1) {
				/* gggbbbbb.rrrrrggg -> palette index: */
				unsigned short a = *(unsigned short *)s;
				register unsigned char c;
				c = pmap[
					((a & 0x001e) >> 1) |
						((a & 0x0780) >> 3) |
						((a & 0xf000) >> 4)];
					*d = c;
					*(d+BPP1) = c;
					d += 2*BPP1; s += BPP2;
					sdx --;
			}

			/* main bulk of data: */
			while (sdx >= 2) {
				/* gggbbbbb.rrrrrggg.gggbbbbb.rrrrrggg -> 2 palette indices */
				register unsigned int a;
				register unsigned char c;
				a = *(unsigned int *)s;
				c = pmap[
					((a & 0x001e) >> 1) |
						((a & 0x0780) >> 3) |
						((a & 0xf000) >> 4)];
					*(d+0) = c;
					*(d+BPP1) = c;
					c = pmap[
						((a & 0x001e0000) >> 17) |
							((a & 0x07800000) >> 19) |
							((a & 0xf0000000) >> 20)];
						*(d+2*BPP1) = c;
						*(d+3*BPP1) = c;
						d += 2*2*BPP1; s += 2*BPP2;
						sdx -= 2;
			}

			/* the remaining odd pixel: */
			if (sdx) {
				/* gggbbbbb.rrrrrggg -> palette index: */
				unsigned short a = *(unsigned short *)s;
				register unsigned char c;
				c = pmap[
					((a & 0x001e) >> 1) |
						((a & 0x0780) >> 3) |
						((a & 0xf000) >> 4)];
					*d = c;
					*(d+BPP1) = c;
					d += 2*BPP1; s += BPP2;
			}
			s -= src_dx * BPP2;
			d -= src_dx * 2*BPP1;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP1); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}


int RGB555toRGB32 (unsigned char *dest_ptr, int dest_width, int dest_height,
				   int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				   unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				   int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}

int RGB555toRGB24 (unsigned char *dest_ptr, int dest_width, int dest_height,
				   int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				   unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				   int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}

/*
* RGB555toRGB565() converter:
*  1:1, 2:1
*/
int RGB555toRGB565 (unsigned char *dest_ptr, int dest_width, int dest_height,
					int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
					unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
					int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP2 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP2 + dest_y * dest_pitch;

		/* copy rows: */
		for (i = 0; i < dest_dy; i ++) {

			register int sx = src_x, ddx = dest_dx;

			/* process misaligned pixels first: */
			while ((sx & 3) && ddx) {
				/* gggbbbbb.0rrrrrgg -> gg0bbbbb.rrrrrggg : */
				register unsigned short c = *(unsigned short *)s;
				*(unsigned short *)d = (c & 0x1F) | ((c & 0x7FE0) << 1);
				d += BPP2;  s += BPP2;
				sx ++; ddx --;
			}

			/* main loop: process 4 pixels a time: */
			while (ddx >= 4) {
				register unsigned int a, b;
				a = *(unsigned int *)s;     /* gggbbbbb.0rrrrrgg.gggbbbbb.0rrrrrgg */
				b = *(unsigned int *)(s+4);
				*(unsigned int *)d = (a & 0x1F001F) | ((a & 0x7FE07FE0) << 1);
				*(unsigned int *)(d+4) = (b & 0x1F001F) | ((b & 0x7FE07FE0) << 1);
				d += BPP2*4; s += BPP2*4; ddx -= 4;
			}

			/* process the remaining 1..3 pixels: */
			while (ddx) {
				/* gggbbbbb.0rrrrrgg -> gg0bbbbb.rrrrrggg : */
				register unsigned short c = *(unsigned short *)s;
				*(unsigned short *)d = (c & 0x1F) | ((c & 0x7FE0) << 1);
				d += BPP2;  s += BPP2;
				ddx --;
			}

			/* bump pointers to the next row: */
			s += src_pitch - dest_dx * BPP2;
			d += dest_pitch - dest_dx * BPP2;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP2 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP2 + dest_y * dest_pitch;

		/* stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* stretch a line: */
			register int sx = src_x, sdx = src_dx;

			/* misaligned pixels first: */
			while ((sx & 3) && sdx) {
				/* gggbbbbb.0rrrrrgg -> gg0bbbbb.rrrrrggg : */
				register unsigned short a, b;
				a = *(unsigned short *)s;
				b = (a & 0x1F) | ((a & 0x7FE0) << 1);
				*(unsigned short *)d = b;
				*(unsigned short *)(d+BPP2) = b;
				d += 2*BPP2; s += BPP2;
				sx ++; sdx --;
			}
			/* main bulk of data: */
			while (sdx >= 4) {
				register unsigned int a, b;
				a = *(unsigned int *)s;     /* gggbbbbb.0rrrrrgg.gggbbbbb.0rrrrrgg */
				b = (a & 0x1F001F) | ((a & 0x7FE07FE0) << 1);
				*(unsigned int *)d = (b & 0xFFFF) | (b << 16);
				*(unsigned int *)(d+2*BPP2) = (b & 0xFFFF0000) | (b >> 16);
				a = *(unsigned int *)(s+2*BPP2);
				b = (a & 0x1F001F) | ((a & 0x7FE07FE0) << 1);
				*(unsigned int *)(d+2*2*BPP2) = (b & 0xFFFF) | (b << 16);
				*(unsigned int *)(d+3*2*BPP2) = (b & 0xFFFF0000) | (b >> 16);
				d += 2*4*BPP2; s += 4*BPP2;
				sdx -= 4;
			}
			/* the remaining pixels: */
			while (sdx) {
				/* gggbbbbb.0rrrrrgg -> gg0bbbbb.rrrrrggg : */
				register unsigned short a, b;
				a = *(unsigned short *)s;
				b = (a & 0x1F) | ((a & 0x7FE0) << 1);
				*(unsigned short *)d = b;
				*(unsigned short *)(d+BPP2) = b;
				d += 2*BPP2; s += BPP2;
				sdx --;
			}
			s -= src_dx * BPP2;
			d -= src_dx * 2*BPP2;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP2); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

/*
* RGB555toRGB555() converter:
*  1:1, 2:1
*/
int RGB555toRGB555 (unsigned char *dest_ptr, int dest_width, int dest_height,
					int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
					unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
					int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP2 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP2 + dest_y * dest_pitch;

		/* copy image: */
		for (i = 0; i < dest_dy; i ++) {
			memcpy (d, s, dest_dx * BPP2);  /* copy dest_dx pixels */ /* Flawfinder: ignore */
			s += src_pitch;
			d += dest_pitch;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP2 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP2 + dest_y * dest_pitch;

		/* stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* stretch a line: */
			register int sdx = src_dx;

			/* misaligned pixel first: */
			if (src_x & 1) {
				register unsigned short a;
				a = *(unsigned short *)s;
				*(unsigned short *)d = a;
				*(unsigned short *)(d+BPP2) = a;
				d += 2*BPP2; s += BPP2;
				sdx --;
			}
			/* main bulk of data: */
			while (sdx >= 2) {
				register unsigned int a;
				a = *(unsigned int *)s;
				*(unsigned int *)d = (a & 0xFFFF) | (a << 16);
				*(unsigned int *)(d+2*BPP2) = (a & 0xFFFF0000) | (a >> 16);
				d += 2*2*BPP2; s += 2*BPP2;
				sdx -= 2;
			}
			/* the remaining odd pixel: */
			if (sdx) {
				register unsigned short a;
				a = *(unsigned short *)s;
				*(unsigned short *)d = a;
				*(unsigned short *)(d+BPP2) = a;
				d += 2*BPP2; s += BPP2;
			}
			s -= src_dx * BPP2;
			d -= src_dx * 2*BPP2;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP2); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}

/*
* No dithering yet.
*/
int RGB555toRGB8 (unsigned char *dest_ptr, int dest_width, int dest_height,
				  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				  unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				  int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP2 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP1 + dest_y * dest_pitch;

		/* copy rows: */
		for (i = 0; i < dest_dy; i ++) {

			register int ddx = dest_dx;

			/* first odd pixel: */
			if (src_x & 1) {
				/* gggbbbbb.0rrrrrgg -> palette index: */
				unsigned short a = *(unsigned short *)s;
				*d = pmap[
					((a & 0x001e) >> 1) |
						((a & 0x03c0) >> 2) |
						((a & 0x7800) >> 3)];
					d += BPP1; s += BPP2;
					ddx --;
			}

			/* main loop: process 2 pixels a time: */
			while (ddx >= 2) {
				/* gggbbbbb.0rrrrrgg.gggbbbbb.0rrrrrgg -> 2 palette indices */
				register unsigned int a;
				a = *(unsigned int *)s;
				*d = pmap[
					((a & 0x001e) >> 1) |
						((a & 0x03c0) >> 2) |
						((a & 0x7800) >> 3)];
					*(d+BPP1) = pmap[
						((a & 0x001e0000) >> 17) |
							((a & 0x03c00000) >> 18) |
							((a & 0x78000000) >> 19)];
						d += BPP1*2; s += BPP2*2;
						ddx -= 2;
			}

			/* the remaining odd pixel: */
			if (ddx) {
				/* gggbbbbb.0rrrrrgg -> palette index: */
				unsigned short a = *(unsigned short *)s;
				*d = pmap[
					((a & 0x001e) >> 1) |
						((a & 0x03c0) >> 2) |
						((a & 0x7800) >> 3)];
					d += BPP1; s += BPP2;
					ddx --;
			}

			/* bump pointers to the next row: */
			s += src_pitch - dest_dx * BPP2;
			d += dest_pitch - dest_dx * BPP1;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP2 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP1 + dest_y * dest_pitch;

		/* stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* stretch a line: */
			register int sdx = src_dx;

			/* first odd pixel: */
			if (src_x & 1) {
				/* gggbbbbb.0rrrrrgg -> palette index: */
				unsigned short a = *(unsigned short *)s;
				register unsigned char c;
				c = pmap[
					((a & 0x001e) >> 1) |
						((a & 0x03c0) >> 2) |
						((a & 0x7800) >> 3)];
					*d = c;
					*(d+BPP1) = c;
					d += 2*BPP1; s += BPP2;
					sdx --;
			}

			/* main bulk of data: */
			while (sdx >= 2) {
				/* gggbbbbb.0rrrrrgg.gggbbbbb.0rrrrrgg -> 2 palette indices */
				register unsigned int a;
				register unsigned char c;
				a = *(unsigned int *)s;
				c = pmap[
					((a & 0x001e) >> 1) |
						((a & 0x03c0) >> 2) |
						((a & 0x7800) >> 3)];
					*(d+0) = c;
					*(d+BPP1) = c;
					c = pmap[
						((a & 0x001e0000) >> 17) |
							((a & 0x03c00000) >> 18) |
							((a & 0x78000000) >> 19)];
						*(d+2*BPP1) = c;
						*(d+3*BPP1) = c;
						d += 2*2*BPP1; s += 2*BPP2;
						sdx -= 2;
			}

			/* the remaining odd pixel: */
			if (sdx) {
				/* gggbbbbb.0rrrrrgg -> palette index: */
				unsigned short a = *(unsigned short *)s;
				register unsigned char c;
				c = pmap[
					((a & 0x001e) >> 1) |
						((a & 0x03c0) >> 2) |
						((a & 0x7800) >> 3)];
					*d = c;
					*(d+BPP1) = c;
					d += 2*BPP1; s += BPP2;
			}
			s -= src_dx * BPP2;
			d -= src_dx * 2*BPP1;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP1); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}


int RGB8toRGB32 (unsigned char *dest_ptr, int dest_width, int dest_height,
				 int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				 unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				 int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}

int RGB8toRGB24 (unsigned char *dest_ptr, int dest_width, int dest_height,
				 int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				 unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				 int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}

int RGB8toRGB565 (unsigned char *dest_ptr, int dest_width, int dest_height,
				  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				  unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				  int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}

int RGB8toRGB555 (unsigned char *dest_ptr, int dest_width, int dest_height,
				  int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				  unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				  int src_x, int src_y, int src_dx, int src_dy)
{
	return -1;   /* not implemented yet... */
}

/*
* RGB8toRGB8() converter:
*  1:1, 2:1
*/
int RGB8toRGB8 (unsigned char *dest_ptr, int dest_width, int dest_height,
				int dest_pitch, int dest_x, int dest_y, int dest_dx, int dest_dy,
				unsigned char *src_ptr, int src_width, int src_height, int src_pitch,
				int src_x, int src_y, int src_dx, int src_dy)
{
	/* scale factors: */
	int scale_x, scale_y;

	/* check arguments: */
	if (!chk_args (dest_ptr, dest_width, dest_height, dest_pitch,
		dest_x, dest_y, dest_dx, dest_dy, src_ptr, src_width, src_height,
		src_pitch, src_x, src_y, src_dx, src_dy, &scale_x, &scale_y))
		return -1;

	/* check if bottom-up bitmaps: */
	if (src_pitch < 0)  src_ptr -= (src_height-1) * src_pitch;
	if (dest_pitch < 0) dest_ptr -= (dest_height-1) * dest_pitch;

	/* check if 1:1 scale: */
	if (scale_x == 1 && scale_y == 1) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP1 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP1 + dest_y * dest_pitch;

		/* copy image: */
		for (i = 0; i < dest_dy; i ++) {
			memcpy (d, s, dest_dx * BPP1);  /* copy dest_dx pixels */ /* Flawfinder: ignore */
			s += src_pitch;
			d += dest_pitch;
		}
		return 0;
	}

	/* check if 2:1 scale: */
	if (scale_x == 2 && scale_y == 2) {

		/* local variables: */
		unsigned char *s, *d;
		register int i;

		/* get pointers: */
		s = src_ptr + src_x * BPP1 + src_y * src_pitch;
		d = dest_ptr + dest_x * BPP1 + dest_y * dest_pitch;

		/* stretch image: */
		for (i = 0; i < src_dy; i ++) {

			/* stretch a line: */
			register int sx = src_x, sdx = src_dx;

			/* misaligned pixels first: */
			while ((sx & 3) && sdx) {
				register unsigned char a;
				a = *s; *d = a; *(d+BPP1) = a;
				d += 2*BPP1; s += BPP1;
				sx ++; sdx --;
			}
			/* main bulk of data: */
			while (sdx >= 4) {
				register unsigned int a;
				a = *(unsigned int *)s;
				*(unsigned int *)d = (a & 0xFF) | ((a & 0xFFFF) << 8) | ((a & 0xFF00) << 16);
				*(unsigned int *)(d+4*BPP1) = (a & 0xFF000000) | ((a & 0xFFFF0000) >> 8) | ((a & 0xFF0000) >> 16);
				d += 2*4*BPP1; s += 4*BPP1;
				sdx -= 4;
			}
			/* the remaining 1..3 pixels: */
			while (sdx) {
				register unsigned char a;
				a = *s; *d = a; *(d+BPP1) = a;
				d += 2*BPP1; s += BPP1;
				sdx --;
			}
			s -= src_dx * BPP1;
			d -= src_dx * 2*BPP1;

			/* replicate a line (vertical stretching): */
			memcpy (d + dest_pitch, d, src_dx * 2 * BPP1); /* Flawfinder: ignore */

			/* bump pointers to the next row: */
			s += src_pitch;
			d += dest_pitch * 2;
		}
		return 0;
	}

	/* conversion is not supported */
	return -1;
}


/*
* Old I420->RGB converters:
* Use:
*  void oldI420toRGBXXX (unsigned char *ysrc, unsigned char *usrc,
*          unsigned char *vsrc, int pitchSrc, unsigned char *dst,
*          int width, int height, int pitchDst);
* Input:
*  ysrc, usrc, vsrc - pointers to Y, Cr, and Cb components of the frame
*  pitchSrc - pitch of the input frame (luminance)
*  dst - pointer to an output buffer
*  width, height - the size of frame to convert
*  pitchDst - pitch of the output buffer (in RGB pixels!!!)
* Returns:
*  none.
*/

/* the driver function: */
static int oldI420toRGB (unsigned char *ysrc, unsigned char *usrc, unsigned char *vsrc,
						 int pitchSrc, unsigned char *dst, int width, int height, int pitchDst, int bpp,
						 void (* dbline) (unsigned char *d1, unsigned char *d2, int dest_x,
						 unsigned char *sy1, unsigned char *sy2, unsigned char *su, unsigned char *sv,
						 int src_x, int dx))
{
	unsigned char *sy1, *sy2, *sv, *su, *d1, *d2;
	register int j, pitch = pitchDst * bpp;

	/* bump dest to other end, if bottom-up output: */
	if (pitch < 0)
		dst += -pitch * (height-1);                     /* start of last line */

	/* get pointers: */
	sy1 = ysrc;                                         /* luma offset */
	sy2 = sy1  + pitchSrc;
	su  = usrc;                                         /* chroma offset */
	sv  = vsrc;
	d1  = dst;                                          /* RGB offset */
	d2  = d1 + pitch;

	/* convert aligned portion of the image: */
	for (j = 0; j < height/2; j ++) {

		/* convert two lines a time: */
		(* dbline) (d1, d2, 0, sy1, sy2, su, sv, 0, width);

		sy1 += pitchSrc*2; sy2 += pitchSrc*2;
		su  += pitchSrc/2; sv  += pitchSrc/2;
		d1  += pitch*2; d2  += pitch*2;
	}

	return 0;
}

/* actual converters: */
void oldI420toRGB32 (unsigned char *ysrc, unsigned char *usrc, unsigned char *vsrc,
					 int pitchSrc, unsigned char *dst, int width, int height, int pitchDst)
{
	oldI420toRGB (ysrc, usrc, vsrc, pitchSrc, dst, width, height, pitchDst, 4,
		is_alpha? dblineI420toRGB32alpha: dblineI420toRGB32);
}

void oldI420toRGB24 (unsigned char *ysrc, unsigned char *usrc, unsigned char *vsrc,
					 int pitchSrc, unsigned char *dst, int width, int height, int pitchDst)
{
	oldI420toRGB (ysrc, usrc, vsrc, pitchSrc, dst, width, height, pitchDst, 3,
		is_alpha? dblineI420toRGB24alpha: dblineI420toRGB24);
}

void oldI420toRGB565 (unsigned char *ysrc, unsigned char *usrc, unsigned char *vsrc,
					  int pitchSrc, unsigned char *dst, int width, int height, int pitchDst)
{
	oldI420toRGB (ysrc, usrc, vsrc, pitchSrc, dst, width, height, pitchDst, 2,
		is_alpha? dblineI420toRGB565alpha: dblineI420toRGB565);
}

void oldI420toRGB555 (unsigned char *ysrc, unsigned char *usrc, unsigned char *vsrc,
					  int pitchSrc, unsigned char *dst, int width, int height, int pitchDst)
{
	oldI420toRGB (ysrc, usrc, vsrc, pitchSrc, dst, width, height, pitchDst, 2,
		is_alpha? dblineI420toRGB555alpha: dblineI420toRGB555);
}

/*
* Convert two YUV lines into RGB linebufs.
* Produces two RGB lines per call.
* Output in padded RGB format, needed for SIMD interpolation.
*/
static void convertI420toXRGB (unsigned char *ysrc, unsigned char *usrc, unsigned char *vsrc,
							   unsigned char *buf1, unsigned char *buf2, int width, int pitchSrc)
{
	unsigned char * ysrc2 = ysrc + pitchSrc;

	if (is_alpha) {

		/* use full matrix: */
		for (; width; width -= 2) {

			int ruv, guv, buv, y;

			buv = butab[usrc[0]] + bvtab[vsrc[0]];
			guv = gutab[usrc[0]] + gvtab[vsrc[0]];
			ruv = rutab[usrc[0]] + rvtab[vsrc[0]];

			/* store as |00 RRRRRRRR 000 GGGGGGGG 000 BBBBBBBB| */
			y = ytab[ysrc[0]];
			*(int *)(buf1+0) =
				(CLIP8[y + buv] << 0) |
				(CLIP8[y + guv] << 11) |
				(CLIP8[y + ruv] << 22);

			y = ytab[ysrc[1]];
			*(int *)(buf1+4) =
				(CLIP8[y + buv] << 0) |
				(CLIP8[y + guv] << 11) |
				(CLIP8[y + ruv] << 22);

			y = ytab[ysrc2[0]];
			*(int *)(buf2+0) =
				(CLIP8[y + buv] << 0) |
				(CLIP8[y + guv] << 11) |
				(CLIP8[y + ruv] << 22);


			y = ytab[ysrc2[1]];
			*(int *)(buf2+4) =
				(CLIP8[y + buv] << 0) |
				(CLIP8[y + guv] << 11) |
				(CLIP8[y + ruv] << 22);

			/* next 2x2 block */
			ysrc += 2; ysrc2 += 2;
			usrc += 1; vsrc += 1;
			buf1 += 8; buf2 += 8;
		}

	} else {

		/* no chroma rotation: */
		for (; width; width -= 2) {

			int rv, guv, bu, y;

			bu = butab[usrc[0]];
			guv = gutab[usrc[0]] + gvtab[vsrc[0]];
			rv = rvtab[vsrc[0]];

			/* store as |00 RRRRRRRR 000 GGGGGGGG 000 BBBBBBBB| */
			y = ytab[ysrc[0]];
			*(int *)(buf1+0) =
				(CLIP8[y + bu] << 0) |
				(CLIP8[y + guv] << 11) |
				(CLIP8[y + rv] << 22);

			y = ytab[ysrc[1]];
			*(int *)(buf1+4) =
				(CLIP8[y + bu] << 0) |
				(CLIP8[y + guv] << 11) |
				(CLIP8[y + rv] << 22);

			y = ytab[ysrc2[0]];
			*(int *)(buf2+0) =
				(CLIP8[y + bu] << 0) |
				(CLIP8[y + guv] << 11) |
				(CLIP8[y + rv] << 22);

			y = ytab[ysrc2[1]];
			*(int *)(buf2+4) =
				(CLIP8[y + bu] << 0) |
				(CLIP8[y + guv] << 11) |
				(CLIP8[y + rv] << 22);

			/* next 2x2 block */
			ysrc += 2; ysrc2 += 2;
			usrc += 1; vsrc += 1;
			buf1 += 8; buf2 += 8;
		}
	}
}

/*
* Interpolate and pack RGB lines into final output
* Produces two output lines per call.
* Requires padded RGB for SIMD interpolation.
*/
#define ROUND888 0x00400801

/* RGB32 version: */
static void interpRGB32 (unsigned char *src1, unsigned char *src2,
						 unsigned char *dst1, unsigned char *dst2, int width)
{
	unsigned int a, b, c, d, e, f;
	unsigned int w, x, y, z;

	width >>= 1;                /* two per pass */
	while (--width) {           /* do all but last pair */

		/*
		* Input pels       Output pels
		*  a b e           w  x  y  z
		*  c d f           w' x' y' z'
		*
		* Input stored as 00 RRRRRRRR 000 GGGGGGGG 000 BBBBBBBB
		*/
		/* top line */
		a = *(unsigned int *)(src1+0);
		b = *(unsigned int *)(src1+4);
		e = *(unsigned int *)(src1+8);

		w = a;
		x = a + b + ROUND888;
		y = b;
		z = b + e + ROUND888;

		/* pack and store */
		*(unsigned int *)(dst1+0) =
			((w & 0x000000ff) >> 0) |
			((w & 0x0007f800) >> 3) |
			((w & 0x3fc00000) >> 6);
		*(unsigned int *)(dst1+4) =
			((x & 0x000001fe) >> 1) |
			((x & 0x000ff000) >> 4) |
			((x & 0x7f800000) >> 7);
		*(unsigned int *)(dst1+8) =
			((y & 0x000000ff) >> 0) |
			((y & 0x0007f800) >> 3) |
			((y & 0x3fc00000) >> 6);
		*(unsigned int *)(dst1+12) =
			((z & 0x000001fe) >> 1) |
			((z & 0x000ff000) >> 4) |
			((z & 0x7f800000) >> 7);

		/* bottom line */
		c = *(unsigned int *)(src2+0);
		d = *(unsigned int *)(src2+4);
		f = *(unsigned int *)(src2+8);

		w = a + c + ROUND888;
		x = a + b + c + d + (ROUND888<<1);
		y = b + d + ROUND888;
		z = b + e + d + f + (ROUND888<<1);

		/* pack and store */
		*(unsigned int *)(dst2+0) =
			((w & 0x000001fe) >> 1) |
			((w & 0x000ff000) >> 4) |
			((w & 0x7f800000) >> 7);
		*(unsigned int *)(dst2+4) =
			((x & 0x000003fc) >> 2) |
			((x & 0x001fe000) >> 5) |
			((x & 0xff000000) >> 8);
		*(unsigned int *)(dst2+8) =
			((y & 0x000001fe) >> 1) |
			((y & 0x000ff000) >> 4) |
			((y & 0x7f800000) >> 7);
		*(unsigned int *)(dst2+12) =
			((z & 0x000003fc) >> 2) |
			((z & 0x001fe000) >> 5) |
			((z & 0xff000000) >> 8);

		/* bump pointers to next 2x2 input */
		src1 += 8; src2 += 8;
		dst1 += 16; dst2 += 16;
	}

	/*
	* For last 4 output pels, repeat final input pel
	* for offscreen input.  Equivalent to pixel-doubling the
	* last output pel.
	*/
	/* top line */
	a = *(unsigned int *)(src1+0);
	b = *(unsigned int *)(src1+4);
	e = b;      /* repeat last input pel */

	w = a;
	x = a + b + ROUND888;
	y = b;
	z = b + e + ROUND888;

	/* pack and store */
	*(unsigned int *)(dst1+0) =
		((w & 0x000000ff) >> 0) |
		((w & 0x0007f800) >> 3) |
		((w & 0x3fc00000) >> 6);
	*(unsigned int *)(dst1+4) =
		((x & 0x000001fe) >> 1) |
		((x & 0x000ff000) >> 4) |
		((x & 0x7f800000) >> 7);
	*(unsigned int *)(dst1+8) =
		((y & 0x000000ff) >> 0) |
		((y & 0x0007f800) >> 3) |
		((y & 0x3fc00000) >> 6);
	*(unsigned int *)(dst1+12) =
		((z & 0x000001fe) >> 1) |
		((z & 0x000ff000) >> 4) |
		((z & 0x7f800000) >> 7);

	/* bottom line */
	c = *(unsigned int *)(src2+0);
	d = *(unsigned int *)(src2+4);
	f = d;      /* repeat last input pel */

	w = a + c + ROUND888;
	x = a + b + c + d + (ROUND888<<1);
	y = b + d + ROUND888;
	z = b + e + d + f + (ROUND888<<1);

	/* pack and store */
	*(unsigned int *)(dst2+0) =
		((w & 0x000001fe) >> 1) |
		((w & 0x000ff000) >> 4) |
		((w & 0x7f800000) >> 7);
	*(unsigned int *)(dst2+4) =
		((x & 0x000003fc) >> 2) |
		((x & 0x001fe000) >> 5) |
		((x & 0xff000000) >> 8);
	*(unsigned int *)(dst2+8) =
		((y & 0x000001fe) >> 1) |
		((y & 0x000ff000) >> 4) |
		((y & 0x7f800000) >> 7);
	*(unsigned int *)(dst2+12) =
		((z & 0x000003fc) >> 2) |
		((z & 0x001fe000) >> 5) |
		((z & 0xff000000) >> 8);
}

/* RGB24 version: */
static void interpRGB24 (unsigned char *src1, unsigned char *src2,
						 unsigned char *dst1, unsigned char *dst2, int width)
{
	unsigned int a, b, c, d, e, f;
	unsigned int w, x, y, z;

	width >>= 1;        /* two per pass */
	while (--width) {   /* do all but last pair */

		/*
		* Input pels       Output pels
		*  a b e           w  x  y  z
		*  c d f           w' x' y' z'
		*
		* Input stored as 00 RRRRRRRR 000 GGGGGGGG 000 BBBBBBBB
		*/
		/* top line */
		a = *(unsigned int *)(src1+0);
		b = *(unsigned int *)(src1+4);
		e = *(unsigned int *)(src1+8);

		w = a;
		x = a + b + ROUND888;
		y = b;
		z = b + e + ROUND888;

		/* pack and store */
		*(unsigned int *)(dst1+0) =
			((w & 0x000000ff) >> 0) |
			((w & 0x0007f800) >> 3) |
			((w & 0x3fc00000) >> 6) |
			((x & 0x000001fe) << 23);
		*(unsigned int *)(dst1+4) =
			((x & 0x000ff000) >> 12) |
			((x & 0x7f800000) >> 15) |
			((y & 0x000000ff) << 16) |
			((y & 0x0007f800) << 13);
		*(unsigned int *)(dst1+8) =
			((y & 0x3fc00000) >> 22) |
			((z & 0x000001fe) << 7) |
			((z & 0x000ff000) << 4) |
			((z & 0x7f800000) << 1);

		/* bottom line */
		c = *(unsigned int *)(src2+0);
		d = *(unsigned int *)(src2+4);
		f = *(unsigned int *)(src2+8);

		w = a + c + ROUND888;
		x = a + b + c + d + (ROUND888<<1);
		y = b + d + ROUND888;
		z = b + e + d + f + (ROUND888<<1);

		/* pack and store */
		*(unsigned int *)(dst2+0) =
			((w & 0x000001fe) >> 1) |
			((w & 0x000ff000) >> 4) |
			((w & 0x7f800000) >> 7) |
			((x & 0x000003fc) << 22);
		*(unsigned int *)(dst2+4) =
			((x & 0x001fe000) >> 13) |
			((x & 0xff000000) >> 16) |
			((y & 0x000001fe) << 15) |
			((y & 0x000ff000) << 12);
		*(unsigned int *)(dst2+8) =
			((y & 0x7f800000) >> 23) |
			((z & 0x000003fc) << 6) |
			((z & 0x001fe000) << 3) |
			((z & 0xff000000) << 0);

		/* next 2x2 input block */
		src1 += 8; src2 += 8;
		dst1 += 12; dst2 += 12;
	}

	/*
	* For last 4 output pels, repeat the final input pel for
	* for missing input.  Equivalent to pixel-doubling the
	* last output pel.
	*/
	/* top line */
	a = *(unsigned int *)(src1+0);
	b = *(unsigned int *)(src1+4);
	e = b;      /* repeat last input pel */

	w = a;
	x = a + b + ROUND888;
	y = b;
	z = b + e + ROUND888;

	/* pack and store */
	*(unsigned int *)(dst1+0) =
		((w & 0x000000ff) >> 0) |
		((w & 0x0007f800) >> 3) |
		((w & 0x3fc00000) >> 6) |
		((x & 0x000001fe) << 23);
	*(unsigned int *)(dst1+4) =
		((x & 0x000ff000) >> 12) |
		((x & 0x7f800000) >> 15) |
		((y & 0x000000ff) << 16) |
		((y & 0x0007f800) << 13);
	*(unsigned int *)(dst1+8) =
		((y & 0x3fc00000) >> 22) |
		((z & 0x000001fe) << 7) |
		((z & 0x000ff000) << 4) |
		((z & 0x7f800000) << 1);

	/* bottom line */
	c = *(unsigned int *)(src2+0);
	d = *(unsigned int *)(src2+4);
	f = d;      /* repeat last input pel */

	w = a + c + ROUND888;
	x = a + b + c + d + (ROUND888<<1);
	y = b + d + ROUND888;
	z = b + e + d + f + (ROUND888<<1);

	/* pack and store */
	*(unsigned int *)(dst2+0) =
		((w & 0x000001fe) >> 1) |
		((w & 0x000ff000) >> 4) |
		((w & 0x7f800000) >> 7) |
		((x & 0x000003fc) << 22);
	*(unsigned int *)(dst2+4) =
		((x & 0x001fe000) >> 13) |
		((x & 0xff000000) >> 16) |
		((y & 0x000001fe) << 15) |
		((y & 0x000ff000) << 12);
	*(unsigned int *)(dst2+8) =
		((y & 0x7f800000) >> 23) |
		((z & 0x000003fc) << 6) |
		((z & 0x001fe000) << 3) |
		((z & 0xff000000) << 0);
}

/* RGB565 version: */
static void interpRGB565 (unsigned char *src1, unsigned char *src2,
						  unsigned char *dst1, unsigned char *dst2, int width)
{
	unsigned int a, b, c, d, e, f;
	unsigned int w, x, y, z;

	width >>= 1;        /* two per pass */
	while (--width) {   /* do all but last pair */

		/*
		* Input pels       Output pels
		*  a b e           w  x  y  z
		*  c d f           w' x' y' z'
		*
		* Input stored as 00 RRRRRRRR 000 GGGGGGGG 000 BBBBBBBB
		*/
		/* top line */
		a = *(unsigned int *)(src1+0);
		b = *(unsigned int *)(src1+4);
		e = *(unsigned int *)(src1+8);

		w = a;
		x = a + b;
		y = b;
		z = b + e;

		/* pack and store */
		*(unsigned int *)(dst1+0) =
			((w & 0x000000f8) >> 3) |
			((w & 0x0007e000) >> 8) |
			((w & 0x3e000000) >> 14) |
			((x & 0x000001f0) << 12) |
			((x & 0x000fc000) << 7) |
			((x & 0x7c000000) << 1);
		*(unsigned int *)(dst1+4) =
			((y & 0x000000f8) >> 3) |
			((y & 0x0007e000) >> 8) |
			((y & 0x3e000000) >> 14) |
			((z & 0x000001f0) << 12) |
			((z & 0x000fc000) << 7) |
			((z & 0x7c000000) << 1);

		/* bottom line */
		c = *(unsigned int *)(src2+0);
		d = *(unsigned int *)(src2+4);
		f = *(unsigned int *)(src2+8);

		w = a + c;
		x = a + b + c + d;
		y = b + d;
		z = b + e + d + f;

		/* pack and store */
		*(unsigned int *)(dst2+0) =
			((w & 0x000001f0) >> 4) |
			((w & 0x000fc000) >> 9) |
			((w & 0x7c000000) >> 15) |
			((x & 0x000003e0) << 11) |
			((x & 0x001f8000) << 6) |
			((x & 0xf8000000) << 0);
		*(unsigned int *)(dst2+4) =
			((y & 0x000001f0) >> 4) |
			((y & 0x000fc000) >> 9) |
			((y & 0x7c000000) >> 15) |
			((z & 0x000003e0) << 11) |
			((z & 0x001f8000) << 6) |
			((z & 0xf8000000) << 0);

		/* next 2x2 input block */
		src1 += 8; src2 += 8;
		dst1 += 8; dst2 += 8;
	}

	/*
	* For last 4 output pels, repeat the final input pel for
	* for missing input.  Equivalent to pixel-doubling the
	* last output pel.
	*/
	/* top line */
	a = *(unsigned int *)(src1+0);
	b = *(unsigned int *)(src1+4);
	e = b;      /* repeat last input pel */

	w = a;
	x = a + b;
	y = b;
	z = b + e;

	/* pack and store */
	*(unsigned int *)(dst1+0) =
		((w & 0x000000f8) >> 3) |
		((w & 0x0007e000) >> 8) |
		((w & 0x3e000000) >> 14) |
		((x & 0x000001f0) << 12) |
		((x & 0x000fc000) << 7) |
		((x & 0x7c000000) << 1);
	*(unsigned int *)(dst1+4) =
		((y & 0x000000f8) >> 3) |
		((y & 0x0007e000) >> 8) |
		((y & 0x3e000000) >> 14) |
		((z & 0x000001f0) << 12) |
		((z & 0x000fc000) << 7) |
		((z & 0x7c000000) << 1);

	/* bottom line */
	c = *(unsigned int *)(src2+0);
	d = *(unsigned int *)(src2+4);
	f = d;      /* repeat last input pel */

	w = a + c;
	x = a + b + c + d;
	y = b + d;
	z = b + e + d + f;

	/* pack and store */
	*(unsigned int *)(dst2+0) =
		((w & 0x000001f0) >> 4) |
		((w & 0x000fc000) >> 9) |
		((w & 0x7c000000) >> 15) |
		((x & 0x000003e0) << 11) |
		((x & 0x001f8000) << 6) |
		((x & 0xf8000000) << 0);
	*(unsigned int *)(dst2+4) =
		((y & 0x000001f0) >> 4) |
		((y & 0x000fc000) >> 9) |
		((y & 0x7c000000) >> 15) |
		((z & 0x000003e0) << 11) |
		((z & 0x001f8000) << 6) |
		((z & 0xf8000000) << 0);
}

/* RGB555 version: */
static void interpRGB555 (unsigned char *src1, unsigned char *src2,
						  unsigned char *dst1, unsigned char *dst2, int width)
{
	unsigned int a, b, c, d, e, f;
	unsigned int w, x, y, z;

	width >>= 1;        /* two per pass */
	while (--width) {   /* do all but last pair */

		/*
		* Input pels       Output pels
		*  a b e           w  x  y  z
		*  c d f           w' x' y' z'
		*
		* Input stored as 00 RRRRRRRR 000 GGGGGGGG 000 BBBBBBBB
		*/
		/* top line */
		a = *(unsigned int *)(src1+0);
		b = *(unsigned int *)(src1+4);
		e = *(unsigned int *)(src1+8);

		w = a;
		x = a + b;
		y = b;
		z = b + e;

		/* pack and store */
		*(unsigned int *)(dst1+0) =
			((w & 0x000000f8) >> 3) |
			((w & 0x0007c000) >> 9) |
			((w & 0x3e000000) >> 15) |
			((x & 0x000001f0) << 12) |
			((x & 0x000f8000) << 6) |
			((x & 0x7c000000) << 0);
		*(unsigned int *)(dst1+4) =
			((y & 0x000000f8) >> 3) |
			((y & 0x0007c000) >> 9) |
			((y & 0x3e000000) >> 15) |
			((z & 0x000001f0) << 12) |
			((z & 0x000f8000) << 6) |
			((z & 0x7c000000) << 0);

		/* bottom line */
		c = *(unsigned int *)(src2+0);
		d = *(unsigned int *)(src2+4);
		f = *(unsigned int *)(src2+8);

		w = a + c;
		x = a + b + c + d;
		y = b + d;
		z = b + e + d + f;

		/* pack and store */
		*(unsigned int *)(dst2+0) =
			((w & 0x000001f0) >> 4) |
			((w & 0x000f8000) >> 10) |
			((w & 0x7c000000) >> 16) |
			((x & 0x000003e0) << 11) |
			((x & 0x001f0000) << 5) |
			((x & 0xf8000000) >> 1);
		*(unsigned int *)(dst2+4) =
			((y & 0x000001f0) >> 4) |
			((y & 0x000f8000) >> 10) |
			((y & 0x7c000000) >> 16) |
			((z & 0x000003e0) << 11) |
			((z & 0x001f0000) << 5) |
			((z & 0xf8000000) >> 1);

		/* next 2x2 input block */
		src1 += 8; src2 += 8;
		dst1 += 8; dst2 += 8;
	}

	/*
	* For last 4 output pels, repeat the final input pel for
	* for missing input.  Equivalent to pixel-doubling the
	* last output pel.
	*/
	/* top line */
	a = *(unsigned int *)(src1+0);
	b = *(unsigned int *)(src1+4);
	e = b;      /* repeat last input pel */

	w = a;
	x = a + b;
	y = b;
	z = b + e;

	/* pack and store */
	*(unsigned int *)(dst1+0) =
		((w & 0x000000f8) >> 3) |
		((w & 0x0007c000) >> 9) |
		((w & 0x3e000000) >> 15) |
		((x & 0x000001f0) << 12) |
		((x & 0x000f8000) << 6) |
		((x & 0x7c000000) << 0);
	*(unsigned int *)(dst1+4) =
		((y & 0x000000f8) >> 3) |
		((y & 0x0007c000) >> 9) |
		((y & 0x3e000000) >> 15) |
		((z & 0x000001f0) << 12) |
		((z & 0x000f8000) << 6) |
		((z & 0x7c000000) << 0);

	/* bottom line */
	c = *(unsigned int *)(src2+0);
	d = *(unsigned int *)(src2+4);
	f = d;      /* repeat last input pel */

	w = a + c;
	x = a + b + c + d;
	y = b + d;
	z = b + e + d + f;

	/* pack and store */
	*(unsigned int *)(dst2+0) =
		((w & 0x000001f0) >> 4) |
		((w & 0x000f8000) >> 10) |
		((w & 0x7c000000) >> 16) |
		((x & 0x000003e0) << 11) |
		((x & 0x001f0000) << 5) |
		((x & 0xf8000000) >> 1);
	*(unsigned int *)(dst2+4) =
		((y & 0x000001f0) >> 4) |
		((y & 0x000f8000) >> 10) |
		((y & 0x7c000000) >> 16) |
		((z & 0x000003e0) << 11) |
		((z & 0x001f0000) << 5) |
		((z & 0xf8000000) >> 1);
}

/* the driver function: */
void oldI420toRGBx2 (unsigned char *ysrc, unsigned char *usrc, unsigned char *vsrc,
					 int pitchSrc, unsigned char *dst, int width, int height, int pitchDst, int bpp,
					 void (* interp) (unsigned char *, unsigned char *, unsigned char *, unsigned char *, int))
{
	/* Pointers to the three RGB linebuffers */
	unsigned char *buf[3]; /* Flawfinder: ignore */
	int ibuf = 0;                           /* circular buffer index */

	int dstinc = bpp * 2 * pitchDst;        /* offset to next output line */
	unsigned char *dst2 = dst + bpp * pitchDst;    /* second output line */

	buf[0] = linebuf;
	buf[1] = linebuf + 4 * width;
	buf[2] = linebuf + 8 * width;

	/* Bump dst to other end, if inverting ouput */
	if (pitchDst < 0) {
		dst += bpp * -pitchDst * (2*height - 1);
		dst2 += bpp * -pitchDst * (2*height - 1);
	}

	/* Special case for first 2 lines */
	convertI420toXRGB (ysrc, usrc, vsrc, buf[next[ibuf]], buf[next2[ibuf]], width, pitchSrc);
	ysrc += pitchSrc << 1;                  /* next 2 lines */
	usrc += pitchSrc >> 1;                  /* next line */
	vsrc += pitchSrc >> 1;                  /* next line */

	/* skip first interp */
	ibuf = next[ibuf];                      /* shift buffers */

	(* interp) (buf[ibuf], buf[next[ibuf]], dst, dst2, width);
	dst += dstinc;                          /* next 2 lines */
	dst2 += dstinc;
	ibuf = next[ibuf];                      /* shift buffers */

	height >>= 1;       /* two rows per pass */
	while (--height) {  /* do all but last pair */

		/* Convert 2 lines into bufs */
		convertI420toXRGB (ysrc, usrc, vsrc, buf[next[ibuf]], buf[next2[ibuf]], width, pitchSrc);
		ysrc += pitchSrc << 1;              /* next 2 lines */
		usrc += pitchSrc >> 1;              /* next line */
		vsrc += pitchSrc >> 1;              /* next line */

		/* Interp 2 lines into dst */
		(* interp) (buf[ibuf], buf[next[ibuf]], dst, dst2, width);
		dst += dstinc;                      /* next 2 lines */
		dst2 += dstinc;
		ibuf = next[ibuf];                  /* shift buffers */

		/* Interp 2 lines into dst */
		(* interp) (buf[ibuf], buf[next[ibuf]], dst, dst2, width);
		dst += dstinc;                      /* next 2 lines */
		dst2 += dstinc;
		ibuf = next[ibuf];                  /* shift buffers */
	}

	/* Last 2 lines, repeating last input line */
	(* interp) (buf[ibuf], buf[ibuf], dst, dst2, width);

}

/* actual converters: */
void oldI420toRGB32x2 (unsigned char *ysrc, unsigned char *usrc, unsigned char *vsrc,
					   int pitchSrc, unsigned char *dst, int width, int height, int pitchDst)
{
	oldI420toRGBx2 (ysrc, usrc, vsrc, pitchSrc, dst, width, height, pitchDst, 4, interpRGB32);
}

void oldI420toRGB24x2 (unsigned char *ysrc, unsigned char *usrc, unsigned char *vsrc,
					   int pitchSrc, unsigned char *dst, int width, int height, int pitchDst)
{
	oldI420toRGBx2 (ysrc, usrc, vsrc, pitchSrc, dst, width, height, pitchDst, 3, interpRGB24);
}

void oldI420toRGB565x2 (unsigned char *ysrc, unsigned char *usrc, unsigned char *vsrc,
						int pitchSrc, unsigned char *dst, int width, int height, int pitchDst)
{
	oldI420toRGBx2 (ysrc, usrc, vsrc, pitchSrc, dst, width, height, pitchDst, 2, interpRGB565);
}

void oldI420toRGB555x2 (unsigned char *ysrc, unsigned char *usrc, unsigned char *vsrc,
						int pitchSrc, unsigned char *dst, int width, int height, int pitchDst)
{
	oldI420toRGBx2 (ysrc, usrc, vsrc, pitchSrc, dst, width, height, pitchDst, 2, interpRGB555);
}



/* colorcvt.c -- end of file */



